diff options
137 files changed, 1947 insertions, 632 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a03236f511..7452509d0d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # Copyright (c) 2006, 2017, Oracle and/or its affiliates. -# Copyright (c) 2008, 2020, MariaDB Corporation. +# Copyright (c) 2008, 2021, MariaDB Corporation. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -140,7 +140,7 @@ ENDIF() # NUMA SET(WITH_NUMA "AUTO" CACHE STRING "Build with non-uniform memory access, allowing --innodb-numa-interleave. Options are ON|OFF|AUTO. ON = enabled (requires NUMA library), OFF = disabled, AUTO = enabled if NUMA library found.") -SET(MYSQL_MAINTAINER_MODE "AUTO" CACHE STRING "MySQL maintainer-specific development environment. Options are: ON OFF AUTO.") +SET(MYSQL_MAINTAINER_MODE "AUTO" CACHE STRING "Enable MariaDB maintainer-specific warnings. One of: NO (warnings are disabled) WARN (warnings are enabled) ERR (warnings are errors) AUTO (warnings are errors in Debug only)") # Packaging IF (NOT CPACK_GENERATOR) diff --git a/cmake/maintainer.cmake b/cmake/maintainer.cmake index f50fea22563..0df943be863 100644 --- a/cmake/maintainer.cmake +++ b/cmake/maintainer.cmake @@ -1,5 +1,5 @@ # Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2020, MariaDB +# Copyright (c) 2011, 2021, MariaDB # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA -IF(MSVC) +IF(MYSQL_MAINTAINER_MODE STREQUAL "NO") RETURN() ENDIF() @@ -50,7 +50,7 @@ IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "6.0.0") SET(MY_ERROR_FLAGS ${MY_ERROR_FLAGS} -Wno-error=maybe-uninitialized) ENDIF() -IF(MYSQL_MAINTAINER_MODE MATCHES "OFF") +IF(MYSQL_MAINTAINER_MODE MATCHES "OFF|WARN") RETURN() ELSEIF(MYSQL_MAINTAINER_MODE MATCHES "AUTO") SET(WHERE DEBUG) diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh index 248537ccabb..e358165c44b 100755 --- a/debian/autobake-deb.sh +++ b/debian/autobake-deb.sh @@ -82,6 +82,15 @@ then sed "/Package: mariadb-plugin-rocksdb/,/^$/d" -i debian/control fi +# From Debian Stretch/Ubuntu Bionic onwards dh-systemd is just an empty +# transitional metapackage and the functionality was merged into debhelper. +# In Ubuntu Hirsute is was completely removed, so it can't be referenced anymore. +# Keep using it only on Debian Jessie and Ubuntu Xenial. +if apt-cache madison dh-systemd | grep 'dh-systemd' >/dev/null 2>&1 +then + sed 's/debhelper (>= 9.20160709~),/debhelper (>= 9), dh-systemd,/' -i debian/control +fi + # If rocksdb-tools is not available (before Debian Buster and Ubuntu Disco) # remove the dependency from the RocksDB plugin so it can install properly # and instead ship the one built from MariaDB sources diff --git a/debian/control b/debian/control index a3b01c70701..0b0ba678f15 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ Maintainer: MariaDB Developers <maria-developers@lists.launchpad.net> Build-Depends: bison, cmake, cracklib-runtime <!nocheck>, - debhelper (>= 9), + debhelper (>= 9.20160709~), dh-exec, dh-systemd, flex [amd64], diff --git a/debian/mariadb-server-10.5.postinst b/debian/mariadb-server-10.5.postinst index 40b91505247..9b0120cb58f 100644 --- a/debian/mariadb-server-10.5.postinst +++ b/debian/mariadb-server-10.5.postinst @@ -238,8 +238,8 @@ EOF ;; triggered) - if [ -x "$(command -v systemctl)" ]; then - systemctl daemon-reload + if [ -d /run/systemd/system ]; then + systemctl --system daemon-reload else invoke-rc.d mariadb restart fi diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index 1972bceacb7..1ce61987d3c 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -1061,6 +1061,7 @@ copy_file(ds_ctxt_t *datasink, ds_file_t *dstfile = NULL; datafile_cur_t cursor; xb_fil_cur_result_t res; + DBUG_ASSERT(datasink->datasink->remove); const char *dst_path = (xtrabackup_copy_back || xtrabackup_move_back)? dst_file_path : trim_dotslash(dst_file_path); @@ -1086,6 +1087,7 @@ copy_file(ds_ctxt_t *datasink, if (ds_write(dstfile, cursor.buf, cursor.buf_read)) { goto error; } + DBUG_EXECUTE_IF("copy_file_error", errno=ENOSPC;goto error;); } if (res == XB_FIL_CUR_ERROR) { @@ -1107,6 +1109,7 @@ copy_file(ds_ctxt_t *datasink, error: datafile_close(&cursor); if (dstfile != NULL) { + datasink->datasink->remove(dstfile->path); ds_close(dstfile); } @@ -1151,17 +1154,18 @@ move_file(ds_ctxt_t *datasink, if (my_rename(src_file_path, dst_file_path_abs, MYF(0)) != 0) { if (my_errno == EXDEV) { - bool ret; - ret = copy_file(datasink, src_file_path, - dst_file_path, thread_n); + /* Fallback to copy/unlink */ + if(!copy_file(datasink, src_file_path, + dst_file_path, thread_n)) + return false; msg(thread_n,"Removing %s", src_file_path); if (unlink(src_file_path) != 0) { my_strerror(errbuf, sizeof(errbuf), errno); - msg("Error: unlink %s failed: %s", + msg("Warning: unlink %s failed: %s", src_file_path, errbuf); } - return(ret); + return true; } my_strerror(errbuf, sizeof(errbuf), my_errno); msg("Can not move file %s to %s: %s", diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc index 28aed958c73..95688933324 100644 --- a/extra/mariabackup/backup_mysql.cc +++ b/extra/mariabackup/backup_mysql.cc @@ -44,6 +44,7 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <mysql.h> #include <mysqld.h> #include <my_sys.h> +#include <stdlib.h> #include <string.h> #include <limits> #include "common.h" @@ -107,6 +108,13 @@ xb_mysql_connect() return(NULL); } +#if !defined(DONT_USE_MYSQL_PWD) + if (!opt_password) + { + opt_password=getenv("MYSQL_PWD"); + } +#endif + if (!opt_secure_auth) { mysql_options(connection, MYSQL_SECURE_AUTH, (char *) &opt_secure_auth); diff --git a/extra/mariabackup/datasink.h b/extra/mariabackup/datasink.h index 201bbfd3267..5c82556b9ba 100644 --- a/extra/mariabackup/datasink.h +++ b/extra/mariabackup/datasink.h @@ -50,9 +50,15 @@ struct datasink_struct { ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); int (*write)(ds_file_t *file, const unsigned char *buf, size_t len); int (*close)(ds_file_t *file); + int (*remove)(const char *path); void (*deinit)(ds_ctxt_t *ctxt); }; + +static inline int dummy_remove(const char *) { + return 0; +} + /* Supported datasink types */ typedef enum { DS_TYPE_STDOUT, diff --git a/extra/mariabackup/ds_archive.cc b/extra/mariabackup/ds_archive.cc index c8fcfa1f5f5..3a5081119b3 100644 --- a/extra/mariabackup/ds_archive.cc +++ b/extra/mariabackup/ds_archive.cc @@ -57,6 +57,7 @@ datasink_t datasink_archive = { &archive_open, &archive_write, &archive_close, + &dummy_remove, &archive_deinit }; diff --git a/extra/mariabackup/ds_buffer.cc b/extra/mariabackup/ds_buffer.cc index 308070ab3b3..d6a420951cb 100644 --- a/extra/mariabackup/ds_buffer.cc +++ b/extra/mariabackup/ds_buffer.cc @@ -54,6 +54,7 @@ datasink_t datasink_buffer = { &buffer_open, &buffer_write, &buffer_close, + &dummy_remove, &buffer_deinit }; diff --git a/extra/mariabackup/ds_compress.cc b/extra/mariabackup/ds_compress.cc index 54c49deac16..960bc766b1e 100644 --- a/extra/mariabackup/ds_compress.cc +++ b/extra/mariabackup/ds_compress.cc @@ -75,6 +75,7 @@ datasink_t datasink_compress = { &compress_open, &compress_write, &compress_close, + &dummy_remove, &compress_deinit }; diff --git a/extra/mariabackup/ds_local.cc b/extra/mariabackup/ds_local.cc index 06b061f3646..ddaa213491d 100644 --- a/extra/mariabackup/ds_local.cc +++ b/extra/mariabackup/ds_local.cc @@ -43,12 +43,18 @@ static int local_write(ds_file_t *file, const uchar *buf, size_t len); static int local_close(ds_file_t *file); static void local_deinit(ds_ctxt_t *ctxt); +static int local_remove(const char *path) +{ + return unlink(path); +} + extern "C" { datasink_t datasink_local = { &local_init, &local_open, &local_write, &local_close, + &local_remove, &local_deinit }; } diff --git a/extra/mariabackup/ds_stdout.cc b/extra/mariabackup/ds_stdout.cc index d30c105d258..08776e99329 100644 --- a/extra/mariabackup/ds_stdout.cc +++ b/extra/mariabackup/ds_stdout.cc @@ -40,6 +40,7 @@ datasink_t datasink_stdout = { &stdout_open, &stdout_write, &stdout_close, + &dummy_remove, &stdout_deinit }; diff --git a/extra/mariabackup/ds_tmpfile.cc b/extra/mariabackup/ds_tmpfile.cc index 4851c2f0263..80b9d3bb4d0 100644 --- a/extra/mariabackup/ds_tmpfile.cc +++ b/extra/mariabackup/ds_tmpfile.cc @@ -51,6 +51,7 @@ datasink_t datasink_tmpfile = { &tmpfile_open, &tmpfile_write, &tmpfile_close, + &dummy_remove, &tmpfile_deinit }; diff --git a/extra/mariabackup/ds_xbstream.cc b/extra/mariabackup/ds_xbstream.cc index 7522510ab27..4d165ad11d9 100644 --- a/extra/mariabackup/ds_xbstream.cc +++ b/extra/mariabackup/ds_xbstream.cc @@ -50,6 +50,7 @@ datasink_t datasink_xbstream = { &xbstream_open, &xbstream_write, &xbstream_close, + &dummy_remove, &xbstream_deinit }; diff --git a/extra/mariabackup/innobackupex.cc b/extra/mariabackup/innobackupex.cc index e874890ad27..aaa1ca8de91 100644 --- a/extra/mariabackup/innobackupex.cc +++ b/extra/mariabackup/innobackupex.cc @@ -208,7 +208,8 @@ enum innobackupex_options OPT_STREAM, OPT_TABLES_FILE, OPT_THROTTLE, - OPT_USE_MEMORY + OPT_USE_MEMORY, + OPT_INNODB_FORCE_RECOVERY, }; ibx_mode_t ibx_mode = IBX_MODE_BACKUP; @@ -626,6 +627,16 @@ static struct my_option ibx_long_options[] = 0, GET_LL, REQUIRED_ARG, 100*1024*1024L, 1024*1024L, LONGLONG_MAX, 0, 1024*1024L, 0}, + {"innodb-force-recovery", OPT_INNODB_FORCE_RECOVERY, + "This option starts up the embedded InnoDB instance in crash " + "recovery mode to ignore page corruption; should be used " + "with the \"--apply-log\" option, in emergencies only. The " + "default value is 0. Refer to \"innodb_force_recovery\" server " + "system variable documentation for more details.", + (uchar*)&xtrabackup_innodb_force_recovery, + (uchar*)&xtrabackup_innodb_force_recovery, + 0, GET_ULONG, OPT_ARG, 0, 0, SRV_FORCE_IGNORE_CORRUPT, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -671,6 +682,7 @@ innobackupex [--compress] [--compress-threads=NUMBER-OF-THREADS] [--compress-chu innobackupex --apply-log [--use-memory=B]\n\ [--defaults-file=MY.CNF]\n\ [--export] [--ibbackup=IBBACKUP-BINARY]\n\ + [--innodb-force-recovery=1]\n\ BACKUP-DIR\n\ \n\ innobackupex --copy-back [--defaults-file=MY.CNF] [--defaults-group=GROUP-NAME] BACKUP-DIR\n\ diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 37791d9dca7..c392ca70ed6 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -262,6 +262,12 @@ static char *xtrabackup_debug_sync = NULL; my_bool xtrabackup_incremental_force_scan = FALSE; +/* + * Ignore corrupt pages (disabled by default; used + * by "innobackupex" as a command line argument). + */ +ulong xtrabackup_innodb_force_recovery = 0; + /* The flushed lsn which is read from data files */ lsn_t flushed_lsn= 0; @@ -1013,7 +1019,8 @@ enum options_xtrabackup OPT_BACKUP_ROCKSDB, OPT_XTRA_CHECK_PRIVILEGES, OPT_XTRA_MYSQLD_ARGS, - OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION + OPT_XB_IGNORE_INNODB_PAGE_CORRUPTION, + OPT_INNODB_FORCE_RECOVERY }; struct my_option xb_client_options[]= { @@ -1633,6 +1640,13 @@ struct my_option xb_server_options[] = &opt_check_privileges, &opt_check_privileges, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, + {"innodb_force_recovery", OPT_INNODB_FORCE_RECOVERY, + "(for --prepare): Crash recovery mode (ignores " + "page corruption; for emergencies only).", + (G_PTR*)&srv_force_recovery, + (G_PTR*)&srv_force_recovery, + 0, GET_ULONG, OPT_ARG, 0, 0, SRV_FORCE_IGNORE_CORRUPT, 0, 0, 0}, + {"mysqld-args", OPT_XTRA_MYSQLD_ARGS, "All arguments that follow this argument are considered as server " "options, and if some of them are not supported by mariabackup, they " @@ -1769,31 +1783,33 @@ static int prepare_export() // Process defaults-file , it can have some --lc-language stuff, // which is* unfortunately* still necessary to get mysqld up - if (strncmp(orig_argv1,"--defaults-file=",16) == 0) + if (strncmp(orig_argv1,"--defaults-file=", 16) == 0) { snprintf(cmdline, sizeof cmdline, - IF_WIN("\"","") "\"%s\" --mysqld \"%s\" " + IF_WIN("\"","") "\"%s\" --mysqld \"%s\"" " --defaults-extra-file=./backup-my.cnf --defaults-group-suffix=%s --datadir=." " --innodb --innodb-fast-shutdown=0 --loose-partition" " --innodb_purge_rseg_truncate_frequency=1 --innodb-buffer-pool-size=%llu" - " --console --skip-log-error --skip-log-bin --bootstrap < " + " --console --skip-log-error --skip-log-bin --bootstrap %s< " BOOTSTRAP_FILENAME IF_WIN("\"",""), - mariabackup_exe, + mariabackup_exe, orig_argv1, (my_defaults_group_suffix?my_defaults_group_suffix:""), - xtrabackup_use_memory); + xtrabackup_use_memory, + (srv_force_recovery ? "--innodb-force-recovery=1 " : "")); } else { - sprintf(cmdline, - IF_WIN("\"","") "\"%s\" --mysqld" + snprintf(cmdline, sizeof cmdline, + IF_WIN("\"","") "\"%s\" --mysqld" " --defaults-file=./backup-my.cnf --defaults-group-suffix=%s --datadir=." " --innodb --innodb-fast-shutdown=0 --loose-partition" " --innodb_purge_rseg_truncate_frequency=1 --innodb-buffer-pool-size=%llu" - " --console --log-error= --skip-log-bin --bootstrap < " + " --console --log-error= --skip-log-bin --bootstrap %s< " BOOTSTRAP_FILENAME IF_WIN("\"",""), mariabackup_exe, (my_defaults_group_suffix?my_defaults_group_suffix:""), - xtrabackup_use_memory); + xtrabackup_use_memory, + (srv_force_recovery ? "--innodb-force-recovery=1 " : "")); } msg("Prepare export : executing %s\n", cmdline); @@ -1940,6 +1956,13 @@ xb_get_one_option(const struct my_option *opt, ADD_PRINT_PARAM_OPT(innobase_buffer_pool_filename); break; + case OPT_INNODB_FORCE_RECOVERY: + + if (srv_force_recovery) { + ADD_PRINT_PARAM_OPT(srv_force_recovery); + } + break; + case OPT_XTRA_TARGET_DIR: strmake(xtrabackup_real_target_dir,argument, sizeof(xtrabackup_real_target_dir)-1); xtrabackup_target_dir= xtrabackup_real_target_dir; @@ -2178,6 +2201,29 @@ static bool innodb_init_param() srv_undo_dir = (char*) "."; } + compile_time_assert(SRV_FORCE_IGNORE_CORRUPT == 1); + + /* + * This option can be read both from the command line, and the + * defaults file. The assignment should account for both cases, + * and for "--innobackupex". Since the command line argument is + * parsed after the defaults file, it takes precedence. + */ + if (xtrabackup_innodb_force_recovery) { + srv_force_recovery = xtrabackup_innodb_force_recovery; + } + + if (srv_force_recovery >= SRV_FORCE_IGNORE_CORRUPT) { + if (!xtrabackup_prepare) { + msg("mariabackup: The option \"innodb_force_recovery\"" + " should only be used with \"%s\".", + (innobackupex_mode ? "--apply-log" : "--prepare")); + goto error; + } else { + msg("innodb_force_recovery = %lu", srv_force_recovery); + } + } + #ifdef _WIN32 srv_use_native_aio = TRUE; #endif @@ -6417,6 +6463,8 @@ int main(int argc, char **argv) char **client_defaults; char **backup_defaults; + my_getopt_prefix_matching= 0; + if (get_exepath(mariabackup_exe,FN_REFLEN, argv[0])) strncpy(mariabackup_exe,argv[0], FN_REFLEN-1); diff --git a/extra/mariabackup/xtrabackup.h b/extra/mariabackup/xtrabackup.h index aff7d1cb287..9842d1eb8ee 100644 --- a/extra/mariabackup/xtrabackup.h +++ b/extra/mariabackup/xtrabackup.h @@ -174,6 +174,8 @@ enum binlog_info_enum { BINLOG_INFO_OFF, BINLOG_INFO_ON, extern ulong opt_binlog_info; +extern ulong xtrabackup_innodb_force_recovery; + void xtrabackup_io_throttling(void); my_bool xb_write_delta_metadata(const char *filename, const xb_delta_info_t *info); diff --git a/mysql-test/include/icp_tests.inc b/mysql-test/include/icp_tests.inc index bfa09e1c01e..d78fe0dd209 100644 --- a/mysql-test/include/icp_tests.inc +++ b/mysql-test/include/icp_tests.inc @@ -487,11 +487,11 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES (1,9),(2,7),(3,6),(4,3),(5,1); -EXPLAIN SELECT pk, c1 FROM t1 WHERE pk <> 3; +EXPLAIN SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); SET SESSION optimizer_switch='index_condition_pushdown=off'; -SELECT pk, c1 FROM t1 WHERE pk <> 3; +SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); DROP TABLE t1; @@ -733,17 +733,17 @@ insert into t2 select seq from seq_1_to_100; SET SESSION optimizer_switch='index_condition_pushdown=off'; --replace_column 9 # EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; SET SESSION optimizer_switch='index_condition_pushdown=on'; --replace_column 9 # EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; DROP TABLE t1,t2; diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm index 473b21441e2..8144a6ef02e 100644 --- a/mysql-test/lib/mtr_report.pm +++ b/mysql-test/lib/mtr_report.pm @@ -497,23 +497,21 @@ sub mtr_report_stats ($$$$) { $test_time = sprintf("%.3f", $test->{timer} / 1000); $test->{'name'} =~ s/$current_suite\.//; - my $test_result; - - # if a test case has to be retried it should have the result MTR_RES_FAILED in jUnit XML - if ($test->{'retries'} > 0) { - $test_result = "MTR_RES_FAILED"; + my $combinations; + if (defined($test->{combinations})){ + $combinations = join ',', sort @{$test->{combinations}}; } else { - $test_result = $test->{'result'}; + $combinations = ""; } - $xml_report .= qq(\t\t<testcase assertions="" classname="$current_suite" name="$test->{'name'}" status="$test_result" time="$test_time"); + $xml_report .= qq(\t\t<testcase assertions="" classname="$current_suite" name="$test->{'name'}" ). + qq(status="$test->{'result'}" time="$test_time" combinations="$combinations"); - my $comment = $test->{'comment'}; - $comment =~ s/[\"]//g; + my $comment= replace_special_symbols($test->{'comment'}); - # if a test case has to be retried it should have the result MTR_RES_FAILED in jUnit XML - if ($test->{'result'} eq "MTR_RES_FAILED" || $test->{'retries'} > 0) { + if ($test->{'result'} eq "MTR_RES_FAILED") { my $logcontents = $test->{'logfile-failed'} || $test->{'logfile'}; + $logcontents= $logcontents.$test->{'warnings'}."\n"; # remove any double ] that would end the cdata $logcontents =~ s/]]/\x{fffd}/g; # replace wide characters that aren't allowed in XML 1.0 @@ -576,6 +574,16 @@ sub mtr_print_line () { print '-' x 74 . "\n"; } +sub replace_special_symbols($) { + my $text= shift; + $text =~ s/&/&/g; + $text =~ s/'/'/g; + $text =~ s/"/"/g; + $text =~ s/</</g; + $text =~ s/>/>/g; + return $text; +} + sub mtr_print_thick_line { my $char= shift || '='; diff --git a/mysql-test/main/derived_opt.result b/mysql-test/main/derived_opt.result index 9da9e6e4413..cf0c1cb617f 100644 --- a/mysql-test/main/derived_opt.result +++ b/mysql-test/main/derived_opt.result @@ -540,4 +540,31 @@ id select_type table type possible_keys key key_len ref rows Extra set join_cache_level=default; set optimizer_switch= @save_optimizer_switch; DROP TABLE t1,t2; +set @save_optimizer_switch= @@optimizer_switch; +set optimizer_switch="derived_merge=on"; +CREATE TABLE t1 (id int, d2 datetime, id1 int) ; +insert into t1 values (1,'2020-01-01 10:10:10',1),(2,'2020-01-01 10:10:10',2),(3,'2020-01-01 10:10:10',3); +CREATE TABLE t2 (id int, d1 datetime, id1 int) ; +insert into t2 values (1,'2020-01-01 10:10:10',1),(2,'2020-01-01 10:10:10',2),(3,'2020-01-01 10:10:10',2); +prepare stmt from " +SELECT * from + (SELECT min(d2) AS d2, min(d1) AS d1 FROM + (SELECT t1.d2 AS d2, (SELECT t2.d1 + FROM t2 WHERE t1.id1 = t2.id1 + ORDER BY t2.id DESC LIMIT 1) AS d1 + FROM t1 + ) dt2 + ) ca + ORDER BY ca.d2;"; +execute stmt; +d2 d1 +2020-01-01 10:10:10 2020-01-01 10:10:10 +execute stmt; +d2 d1 +2020-01-01 10:10:10 2020-01-01 10:10:10 +set optimizer_switch= @save_optimizer_switch; +DROP TABLE t1, t2; +# +# End of 10.3 tests +# set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/main/derived_opt.test b/mysql-test/main/derived_opt.test index eccf4c13020..dee424559ee 100644 --- a/mysql-test/main/derived_opt.test +++ b/mysql-test/main/derived_opt.test @@ -406,5 +406,38 @@ set optimizer_switch= @save_optimizer_switch; DROP TABLE t1,t2; +# +# MDEV-25182: Complex query in Store procedure corrupts results +# +set @save_optimizer_switch= @@optimizer_switch; +set optimizer_switch="derived_merge=on"; + +CREATE TABLE t1 (id int, d2 datetime, id1 int) ; +insert into t1 values (1,'2020-01-01 10:10:10',1),(2,'2020-01-01 10:10:10',2),(3,'2020-01-01 10:10:10',3); + +CREATE TABLE t2 (id int, d1 datetime, id1 int) ; +insert into t2 values (1,'2020-01-01 10:10:10',1),(2,'2020-01-01 10:10:10',2),(3,'2020-01-01 10:10:10',2); + +prepare stmt from " +SELECT * from + (SELECT min(d2) AS d2, min(d1) AS d1 FROM + (SELECT t1.d2 AS d2, (SELECT t2.d1 + FROM t2 WHERE t1.id1 = t2.id1 + ORDER BY t2.id DESC LIMIT 1) AS d1 + FROM t1 + ) dt2 + ) ca + ORDER BY ca.d2;"; + +execute stmt; +execute stmt; + +set optimizer_switch= @save_optimizer_switch; +DROP TABLE t1, t2; + +--echo # +--echo # End of 10.3 tests +--echo # + # The following command must be the last one the file set optimizer_switch=@exit_optimizer_switch; diff --git a/mysql-test/main/func_group.result b/mysql-test/main/func_group.result index 0f09aedc22a..177f0950a77 100644 --- a/mysql-test/main/func_group.result +++ b/mysql-test/main/func_group.result @@ -606,7 +606,7 @@ select min(a1) from t1 where a1 > 'KKK' or a1 < 'XXX'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 0 NULL 15 Using where; Using index explain -select min(a1) from t1 where a1 != 'KKK'; +select min(a1) from t1 where (a1 < 'KKK' or a1 > 'KKK'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 3 NULL 14 Using where; Using index explain diff --git a/mysql-test/main/func_group.test b/mysql-test/main/func_group.test index 10b92cbadca..a28b39c28f6 100644 --- a/mysql-test/main/func_group.test +++ b/mysql-test/main/func_group.test @@ -359,7 +359,7 @@ select min(t1.a1), min(t2.a4) from t1,t2 where t1.a1 < 'KKK' and t2.a4 < 'KKK'; explain select min(a1) from t1 where a1 > 'KKK' or a1 < 'XXX'; explain -select min(a1) from t1 where a1 != 'KKK'; +select min(a1) from t1 where (a1 < 'KKK' or a1 > 'KKK'); explain select max(a3) from t1 where a2 < 2 and a3 < 'SEA'; explain diff --git a/mysql-test/main/group_min_max.result b/mysql-test/main/group_min_max.result index 4f32db780fd..a17f3f09c3b 100644 --- a/mysql-test/main/group_min_max.result +++ b/mysql-test/main/group_min_max.result @@ -2942,7 +2942,7 @@ NULL EXPLAIN SELECT MIN( a ) FROM t1 WHERE a <> NULL; id select_type table type possible_keys key key_len ref rows Extra -x x x x x x x x x Impossible WHERE noticed after reading const tables +x x x x x x x x x Using where; Using index SELECT MIN( a ) FROM t1 WHERE a <> NULL; MIN( a ) NULL diff --git a/mysql-test/main/index_merge_myisam.result b/mysql-test/main/index_merge_myisam.result index 1a4906801a0..053239b7fb1 100644 --- a/mysql-test/main/index_merge_myisam.result +++ b/mysql-test/main/index_merge_myisam.result @@ -1687,7 +1687,8 @@ INSERT INTO t1 VALUES ALTER TABLE t1 ENABLE KEYS; EXPLAIN SELECT * FROM t1 FORCE KEY (PRIMARY , i , c1 , c2) -WHERE pk = 255 OR i = 22 OR (pk IN (1 , 136) AND c2 IN ('c' , 'w') AND (c1 NOT BETWEEN 'e' AND 'i' OR c2 > 'g')) OR pk != 1 ; +WHERE pk = 255 OR i = 22 OR (pk IN (1 , 136) AND c2 IN ('c' , 'w') AND (c1 +NOT BETWEEN 'e' AND 'i' OR c2 > 'g')) OR (pk is not null and (pk <1 or pk>1)) ; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge PRIMARY,c1,i,c2 PRIMARY,i 0,5 NULL 69 Using sort_union(PRIMARY,i); Using where DROP TABLE t1; diff --git a/mysql-test/main/index_merge_myisam.test b/mysql-test/main/index_merge_myisam.test index e35ce567573..10ddbee36b2 100644 --- a/mysql-test/main/index_merge_myisam.test +++ b/mysql-test/main/index_merge_myisam.test @@ -236,9 +236,11 @@ INSERT INTO t1 VALUES ALTER TABLE t1 ENABLE KEYS; +# note: (pk is not null and (pk <1 or pk>1)) below is a sargable form of pk!=1 EXPLAIN SELECT * FROM t1 FORCE KEY (PRIMARY , i , c1 , c2) -WHERE pk = 255 OR i = 22 OR (pk IN (1 , 136) AND c2 IN ('c' , 'w') AND (c1 NOT BETWEEN 'e' AND 'i' OR c2 > 'g')) OR pk != 1 ; +WHERE pk = 255 OR i = 22 OR (pk IN (1 , 136) AND c2 IN ('c' , 'w') AND (c1 +NOT BETWEEN 'e' AND 'i' OR c2 > 'g')) OR (pk is not null and (pk <1 or pk>1)) ; DROP TABLE t1; diff --git a/mysql-test/main/innodb_icp.result b/mysql-test/main/innodb_icp.result index adf65780d21..c89d49cad0c 100644 --- a/mysql-test/main/innodb_icp.result +++ b/mysql-test/main/innodb_icp.result @@ -455,11 +455,11 @@ c1 INT NOT NULL, PRIMARY KEY (pk) ); INSERT INTO t1 VALUES (1,9),(2,7),(3,6),(4,3),(5,1); -EXPLAIN SELECT pk, c1 FROM t1 WHERE pk <> 3; +EXPLAIN SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 4 Using where SET SESSION optimizer_switch='index_condition_pushdown=off'; -SELECT pk, c1 FROM t1 WHERE pk <> 3; +SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); pk c1 1 9 2 7 @@ -689,23 +689,23 @@ INSERT INTO t2 VALUES insert into t2 select seq from seq_1_to_100; SET SESSION optimizer_switch='index_condition_pushdown=off'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 SET SESSION optimizer_switch='index_condition_pushdown=on'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 diff --git a/mysql-test/main/myisam_icp.result b/mysql-test/main/myisam_icp.result index f059c3f95e5..d0614913480 100644 --- a/mysql-test/main/myisam_icp.result +++ b/mysql-test/main/myisam_icp.result @@ -448,11 +448,11 @@ c1 INT NOT NULL, PRIMARY KEY (pk) ); INSERT INTO t1 VALUES (1,9),(2,7),(3,6),(4,3),(5,1); -EXPLAIN SELECT pk, c1 FROM t1 WHERE pk <> 3; +EXPLAIN SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 5 Using where SET SESSION optimizer_switch='index_condition_pushdown=off'; -SELECT pk, c1 FROM t1 WHERE pk <> 3; +SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); pk c1 1 9 2 7 @@ -682,23 +682,23 @@ INSERT INTO t2 VALUES insert into t2 select seq from seq_1_to_100; SET SESSION optimizer_switch='index_condition_pushdown=off'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 SET SESSION optimizer_switch='index_condition_pushdown=on'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 diff --git a/mysql-test/main/mysqldump-nl.test b/mysql-test/main/mysqldump-nl.test index 863c846b9a6..4451b0605c2 100644 --- a/mysql-test/main/mysqldump-nl.test +++ b/mysql-test/main/mysqldump-nl.test @@ -26,10 +26,10 @@ create procedure sp() select * from `v1 flush tables; use test; -exec $MYSQL_DUMP --compact --comment --routines --add-drop-database --databases 'mysqltest1 +exec $MYSQL_DUMP --compact --comments --routines --add-drop-database --databases 'mysqltest1 1tsetlqsym'; -exec $MYSQL_DUMP --compact --comment --routines --add-drop-database --databases 'mysqltest1 +exec $MYSQL_DUMP --compact --comments --routines --add-drop-database --databases 'mysqltest1 1tsetlqsym' | $MYSQL; show tables from `mysqltest1 @@ -45,11 +45,11 @@ create database `test\`` show databases like 'test%'; -exec $MYSQL_DUMP --compact --comment --add-drop-database --databases 'test`' 'test\` +exec $MYSQL_DUMP --compact --comments --add-drop-database --databases 'test`' 'test\` \! ls #'; -exec $MYSQL_DUMP --compact --comment --add-drop-database --databases 'test`' 'test\` +exec $MYSQL_DUMP --compact --comments --add-drop-database --databases 'test`' 'test\` \! ls #' | $MYSQL; diff --git a/mysql-test/main/parser_not_embedded.test b/mysql-test/main/parser_not_embedded.test index 3ebd23e888e..3af1260f4ad 100644 --- a/mysql-test/main/parser_not_embedded.test +++ b/mysql-test/main/parser_not_embedded.test @@ -21,7 +21,7 @@ select 7 as expected, /*!01000 1 + /*!01000 8 + /*!01000 error */ 16 + */ 2 + */ select 4 as expected, /* 1 + /*!01000 8 + */ 2 + */ 4; EOF ---exec $MYSQL --comment --force --table test <$MYSQLTEST_VARDIR/tmp/bug39559.sql +--exec $MYSQL --comments --force --table test <$MYSQLTEST_VARDIR/tmp/bug39559.sql --remove_file $MYSQLTEST_VARDIR/tmp/bug39559.sql --echo # Bug#46527 "COMMIT AND CHAIN RELEASE does not make sense" diff --git a/mysql-test/main/ps.result b/mysql-test/main/ps.result index 1c13b0a0b84..6b2586e9be6 100644 --- a/mysql-test/main/ps.result +++ b/mysql-test/main/ps.result @@ -5514,6 +5514,43 @@ id select_type table type possible_keys key key_len ref rows Extra DEALLOCATE PREPARE stmt; DROP TABLE t1; # +# MDEV-25108: Running of the EXPLAIN EXTENDED statement produces extra warning +# in case it is executed in PS (prepared statement) mode +# +CREATE TABLE t1 (c int); +CREATE TABLE t2 (d int); +# EXPLAIN EXTENDED in regular way (not PS mode) +EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system NULL NULL NULL NULL 0 0.00 Const row not found +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1 +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1` +SHOW WARNINGS; +Level Code Message +Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1 +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1` +# Now run the same EXPLAIN EXTENDED in PS mode. Number of warnings +# and their content must be the same as in case running the statement +# in regular way +PREPARE stmt FROM "EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1"; +Warnings: +Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1 +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY t1 system NULL NULL NULL NULL 0 0.00 Const row not found +2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +Warnings: +Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1 +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1` +SHOW WARNINGS; +Level Code Message +Note 1276 Field or reference 'test.t1.c' of SELECT #2 was resolved in SELECT #1 +Note 1003 /* select#1 */ select (/* select#2 */ select 1 from `test`.`t2` where 0) AS `(SELECT 1 FROM t2 WHERE d = c)` from `test`.`t1` +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; +# # End of 10.2 tests # # @@ -5532,5 +5569,37 @@ DEALLOCATE PREPARE stmt; DROP VIEW v1; DROP TABLE t1; # +# MDEV-25197: The statement set password=password('') executed in PS mode +# fails in case it is run by a user with expired password +# +CREATE USER user1@localhost PASSWORD EXPIRE; +SET @disconnect_on_expired_password_save=@@global.disconnect_on_expired_password; +SET GLOBAL disconnect_on_expired_password=OFF; +connect con1,localhost,user1; +connection con1; +# Check that no regular statement like SELECT can be prepared +# by a user with an expired password +PREPARE stmt FROM "SELECT 1"; +ERROR HY000: You must SET PASSWORD before executing this statement +# Check that the DEALLOCATE PREPARE statement can be run by a user +# with an expired password +PREPARE stmt FROM "SET password=password('')"; +DEALLOCATE PREPARE stmt; +# Check that the SET PASSWORD statement can be executed in PS mode by +# a user with an expired password +PREPARE stmt FROM "SET password=password('')"; +EXECUTE stmt; +PREPARE stmt FROM "SELECT 1"; +# Check that user's password is not expired anymore +EXECUTE stmt; +1 +1 +DEALLOCATE PREPARE stmt; +# Clean up +disconnect con1; +connection default; +SET GLOBAL disconnect_on_expired_password=@disconnect_on_expired_password_save; +DROP USER user1@localhost; +# # End of 10.4 tests # diff --git a/mysql-test/main/ps.test b/mysql-test/main/ps.test index 2ce78b78e90..2a468d33ace 100644 --- a/mysql-test/main/ps.test +++ b/mysql-test/main/ps.test @@ -4956,6 +4956,26 @@ DEALLOCATE PREPARE stmt; DROP TABLE t1; --echo # +--echo # MDEV-25108: Running of the EXPLAIN EXTENDED statement produces extra warning +--echo # in case it is executed in PS (prepared statement) mode +--echo # +CREATE TABLE t1 (c int); +CREATE TABLE t2 (d int); + +--echo # EXPLAIN EXTENDED in regular way (not PS mode) +EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1; +SHOW WARNINGS; + +--echo # Now run the same EXPLAIN EXTENDED in PS mode. Number of warnings +--echo # and their content must be the same as in case running the statement +--echo # in regular way +PREPARE stmt FROM "EXPLAIN EXTENDED SELECT (SELECT 1 FROM t2 WHERE d = c) FROM t1"; +EXECUTE stmt; +SHOW WARNINGS; + +DEALLOCATE PREPARE stmt; +DROP TABLE t1, t2; +--echo # --echo # End of 10.2 tests --echo # @@ -4980,5 +5000,42 @@ DROP VIEW v1; DROP TABLE t1; --echo # +--echo # MDEV-25197: The statement set password=password('') executed in PS mode +--echo # fails in case it is run by a user with expired password +--echo # +CREATE USER user1@localhost PASSWORD EXPIRE; + +SET @disconnect_on_expired_password_save=@@global.disconnect_on_expired_password; +SET GLOBAL disconnect_on_expired_password=OFF; + +connect(con1,localhost,user1); +connection con1; +--echo # Check that no regular statement like SELECT can be prepared +--echo # by a user with an expired password +--error ER_MUST_CHANGE_PASSWORD +PREPARE stmt FROM "SELECT 1"; + +--echo # Check that the DEALLOCATE PREPARE statement can be run by a user +--echo # with an expired password +PREPARE stmt FROM "SET password=password('')"; +DEALLOCATE PREPARE stmt; + +--echo # Check that the SET PASSWORD statement can be executed in PS mode by +--echo # a user with an expired password +PREPARE stmt FROM "SET password=password('')"; +EXECUTE stmt; +PREPARE stmt FROM "SELECT 1"; +--echo # Check that user's password is not expired anymore +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +--echo # Clean up +disconnect con1; +connection default; + +SET GLOBAL disconnect_on_expired_password=@disconnect_on_expired_password_save; +DROP USER user1@localhost; + +--echo # --echo # End of 10.4 tests --echo # diff --git a/mysql-test/main/range.result b/mysql-test/main/range.result index 8e9b9596e1e..d97cfb2b587 100644 --- a/mysql-test/main/range.result +++ b/mysql-test/main/range.result @@ -3252,6 +3252,17 @@ SELECT * FROM t1 JOIN t2 ON (t2.code = t1.b) WHERE t1.a NOT IN ('baz', 'qux') OR id a b code num DROP TABLE t1, t2; # +# MDEV-23634: Select query hanged the server and leads to OOM ... +# (The fix is to add the same handling for "col!=const" as MDEV-21958 did for NOT IN) +# +create table t1 (pk int primary key, a int); +insert into t1 (pk) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +# must not use range: +explain select * from t1 force index (primary) where pk != 1 and pk!=2 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 10 Using where +drop table t1; +# # MDEV-22251: get_key_scans_params: Conditional jump or move depends on uninitialised value # create table t1 (pk int, i int, v int, primary key (pk), key(v)); diff --git a/mysql-test/main/range.test b/mysql-test/main/range.test index 8e8161cde25..6d43ad9090d 100644 --- a/mysql-test/main/range.test +++ b/mysql-test/main/range.test @@ -2216,6 +2216,17 @@ DROP TABLE t1, t2; --echo # +--echo # MDEV-23634: Select query hanged the server and leads to OOM ... +--echo # (The fix is to add the same handling for "col!=const" as MDEV-21958 did for NOT IN) +--echo # +create table t1 (pk int primary key, a int); +insert into t1 (pk) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); + +--echo # must not use range: +explain select * from t1 force index (primary) where pk != 1 and pk!=2 ; +drop table t1; + +--echo # --echo # MDEV-22251: get_key_scans_params: Conditional jump or move depends on uninitialised value --echo # diff --git a/mysql-test/main/range_mrr_icp.result b/mysql-test/main/range_mrr_icp.result index e24e3bc3903..9fa7bd29851 100644 --- a/mysql-test/main/range_mrr_icp.result +++ b/mysql-test/main/range_mrr_icp.result @@ -3241,6 +3241,17 @@ SELECT * FROM t1 JOIN t2 ON (t2.code = t1.b) WHERE t1.a NOT IN ('baz', 'qux') OR id a b code num DROP TABLE t1, t2; # +# MDEV-23634: Select query hanged the server and leads to OOM ... +# (The fix is to add the same handling for "col!=const" as MDEV-21958 did for NOT IN) +# +create table t1 (pk int primary key, a int); +insert into t1 (pk) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +# must not use range: +explain select * from t1 force index (primary) where pk != 1 and pk!=2 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 10 Using where +drop table t1; +# # MDEV-22251: get_key_scans_params: Conditional jump or move depends on uninitialised value # create table t1 (pk int, i int, v int, primary key (pk), key(v)); diff --git a/mysql-test/main/range_vs_index_merge.result b/mysql-test/main/range_vs_index_merge.result index 6b2c9a2f0bc..207e012b825 100644 --- a/mysql-test/main/range_vs_index_merge.result +++ b/mysql-test/main/range_vs_index_merge.result @@ -1810,11 +1810,11 @@ CREATE TABLE t1 (a int PRIMARY KEY, b int, INDEX idx(b)); INSERT INTO t1 VALUES (167,9999), (168,10000); EXPLAIN SELECT * FROM t1 -WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; +WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY,idx PRIMARY 0 NULL 2 Using index condition; Using where SELECT * FROM t1 -WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; +WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); a b 167 9999 168 10000 @@ -1846,12 +1846,12 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK EXPLAIN SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range state,capital state 71 NULL 8 Using index condition; Using where SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; id state capital 4 Florida Tallahassee diff --git a/mysql-test/main/range_vs_index_merge.test b/mysql-test/main/range_vs_index_merge.test index 5ed5f621ab6..94210ce5dd3 100644 --- a/mysql-test/main/range_vs_index_merge.test +++ b/mysql-test/main/range_vs_index_merge.test @@ -1231,9 +1231,9 @@ INSERT INTO t1 VALUES (167,9999), (168,10000); EXPLAIN SELECT * FROM t1 - WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; + WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); SELECT * FROM t1 - WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; + WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); DROP TABLE t1; @@ -1266,10 +1266,10 @@ ANALYZE TABLE t1; EXPLAIN SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; DROP TABLE t1; diff --git a/mysql-test/main/range_vs_index_merge_innodb.result b/mysql-test/main/range_vs_index_merge_innodb.result index 497aa3d94dc..4ac62e24940 100644 --- a/mysql-test/main/range_vs_index_merge_innodb.result +++ b/mysql-test/main/range_vs_index_merge_innodb.result @@ -1816,11 +1816,11 @@ CREATE TABLE t1 (a int PRIMARY KEY, b int, INDEX idx(b)); INSERT INTO t1 VALUES (167,9999), (168,10000); EXPLAIN SELECT * FROM t1 -WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; +WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index PRIMARY,idx idx 5 NULL 2 Using where; Using index SELECT * FROM t1 -WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR a!=2; +WHERE a BETWEEN 4 AND 5 AND b IN (255,4) OR a IN (2,14,25) OR (a<2 or a>2); a b 167 9999 168 10000 @@ -1852,12 +1852,12 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK EXPLAIN SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range state,capital state 71 NULL 8 Using index condition; Using where SELECT * FROM t1 FORCE KEY (state,capital) -WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND id != 9 +WHERE ( state = 'Alabama' OR state >= 'Colorado' ) AND (id<9 or id>9) OR ( capital >= 'Topeka' OR state = 'Kansas' ) AND state != 'Texas'; id state capital 4 Florida Tallahassee diff --git a/mysql-test/main/selectivity_innodb.result b/mysql-test/main/selectivity_innodb.result index 46723410b75..dc377aa5b6c 100644 --- a/mysql-test/main/selectivity_innodb.result +++ b/mysql-test/main/selectivity_innodb.result @@ -1443,7 +1443,7 @@ EXPLAIN EXTENDED SELECT * FROM t1, t2 WHERE a <> 'USARussian' AND b IS NULL; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 range PRIMARY,b b 23 NULL 2 100.00 Using where; Using index +1 SIMPLE t1 ref PRIMARY,b b 5 const 1 100.00 Using where; Using index 1 SIMPLE t2 ALL NULL NULL NULL NULL 14 100.00 Using join buffer (flat, BNL join) Warnings: Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`i` AS `i` from `test`.`t1` join `test`.`t2` where `test`.`t1`.`a` <> 'USARussian' and `test`.`t1`.`b` is null diff --git a/mysql-test/main/subselect_mat_cost_bugs.result b/mysql-test/main/subselect_mat_cost_bugs.result index 34c0ccab620..6a218ed5e04 100644 --- a/mysql-test/main/subselect_mat_cost_bugs.result +++ b/mysql-test/main/subselect_mat_cost_bugs.result @@ -189,8 +189,8 @@ SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 WHERE ( SELECT t2.f2 -FROM t2 JOIN t1 ON t1.f1 -WHERE t1.f1 AND alias2.f10 +FROM t2 JOIN t1 ON (t1.f1>0 or t1.f1<0) +WHERE (t1.f1>0 or t1.f1<0) AND alias2.f10 ) ORDER BY field1 ; id select_type table type possible_keys key key_len ref rows Extra @@ -203,8 +203,8 @@ SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 WHERE ( SELECT t2.f2 -FROM t2 JOIN t1 ON t1.f1 -WHERE t1.f1 AND alias2.f10 +FROM t2 JOIN t1 ON (t1.f1>0 or t1.f1<0) +WHERE (t1.f1>0 or t1.f1<0) AND alias2.f10 ) ORDER BY field1 ; field1 diff --git a/mysql-test/main/subselect_mat_cost_bugs.test b/mysql-test/main/subselect_mat_cost_bugs.test index 028cdced560..ba1aad06a15 100644 --- a/mysql-test/main/subselect_mat_cost_bugs.test +++ b/mysql-test/main/subselect_mat_cost_bugs.test @@ -217,8 +217,8 @@ SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 WHERE ( SELECT t2.f2 - FROM t2 JOIN t1 ON t1.f1 - WHERE t1.f1 AND alias2.f10 + FROM t2 JOIN t1 ON (t1.f1>0 or t1.f1<0) + WHERE (t1.f1>0 or t1.f1<0) AND alias2.f10 ) ORDER BY field1 ; @@ -226,8 +226,8 @@ SELECT alias2.f2 AS field1 FROM t1 AS alias1 JOIN ( SELECT * FROM t2 ) AS alias2 ON alias2.f3 = alias1.f1 WHERE ( SELECT t2.f2 - FROM t2 JOIN t1 ON t1.f1 - WHERE t1.f1 AND alias2.f10 + FROM t2 JOIN t1 ON (t1.f1>0 or t1.f1<0) + WHERE (t1.f1>0 or t1.f1<0) AND alias2.f10 ) ORDER BY field1 ; diff --git a/mysql-test/main/userstat.result b/mysql-test/main/userstat.result index 6d9cd491de6..9152f602304 100644 --- a/mysql-test/main/userstat.result +++ b/mysql-test/main/userstat.result @@ -243,6 +243,8 @@ create function f() returns int return (select 1 from performance_schema.threads set global userstat= 1; select f() from information_schema.table_statistics; ERROR 21000: Subquery returns more than 1 row +select f() from information_schema.index_statistics; +ERROR 21000: Subquery returns more than 1 row set global userstat= 0; drop function f; # diff --git a/mysql-test/main/userstat.test b/mysql-test/main/userstat.test index cc7ddd58e11..6d486810db1 100644 --- a/mysql-test/main/userstat.test +++ b/mysql-test/main/userstat.test @@ -121,6 +121,8 @@ create function f() returns int return (select 1 from performance_schema.threads set global userstat= 1; --error ER_SUBQUERY_NO_1_ROW select f() from information_schema.table_statistics; +--error ER_SUBQUERY_NO_1_ROW +select f() from information_schema.index_statistics; set global userstat= 0; drop function f; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index fd0e5ffd12a..c5c7ba6d03d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -732,9 +732,13 @@ sub run_test_server ($$$) { rename $log_file_name, $log_file_name.".failed"; } - delete($result->{result}); - $result->{retries}= $retries+1; - $result->write_test($sock, 'TESTCASE'); + { + local @$result{'retries', 'result'}; + delete $result->{result}; + $result->{retries}= $retries+1; + $result->write_test($sock, 'TESTCASE'); + } + push(@$completed, $result); next; } } diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 05eee166a0f..a562f8b0ae7 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -22,7 +22,6 @@ galera_bf_abort_at_after_statement : MDEV-21557: galera_bf_abort_at_after_statem galera_bf_abort_group_commit : MDEV-18282 Galera test failure on galera.galera_bf_abort_group_commit galera_bf_kill_debug : MDEV-24485 wsrep::client_state::do_acquire_ownership(): Assertion `state_ == s_idle || mode_ != m_local' failed galera_bf_lock_wait : MDEV-21597 wsrep::transaction::start_transaction(): Assertion `active() == false' failed -galera_binlog_stmt_autoinc : MDEV-19959 Galera test failure on galera_binlog_stmt_autoinc galera_encrypt_tmp_files : Get error failed to enable encryption of temporary files galera_ftwrl : MDEV-21525 galera.galera_ftwrl galera_gcache_recover_manytrx : MDEV-18834 Galera test failure @@ -34,7 +33,6 @@ galera_pc_ignore_sb : MDEV-20888 galera.galera_pc_ignore_sb galera_pc_recovery : MDEV-25199 cluster fails to start up galera_shutdown_nonprim : MDEV-21493 galera.galera_shutdown_nonprim galera_ssl_upgrade : MDEV-19950 Galera test failure on galera_ssl_upgrade -galera_sst_mariabackup_encrypt_with_key : MDEV-21484 galera_sst_mariabackup_encrypt_with_key galera_toi_ddl_nonconflicting : MDEV-21518 galera.galera_toi_ddl_nonconflicting galera_toi_truncate : MDEV-22996 Hang on galera_toi_truncate test case galera_trigger : MDEV-24048 galera.galera_trigger MTR fails: Result content mismatch diff --git a/mysql-test/suite/galera/r/galera_var_sst_auth.result b/mysql-test/suite/galera/r/galera_var_sst_auth.result index 53b8443705a..98d683c3b2d 100644 --- a/mysql-test/suite/galera/r/galera_var_sst_auth.result +++ b/mysql-test/suite/galera/r/galera_var_sst_auth.result @@ -1,5 +1,7 @@ connection node_2; connection node_1; +connection node_1; +connection node_2; SELECT @@global.wsrep_sst_auth; @@global.wsrep_sst_auth ******** diff --git a/mysql-test/suite/galera/r/galera_virtual_blob.result b/mysql-test/suite/galera/r/galera_virtual_blob.result new file mode 100644 index 00000000000..fd1c84f7083 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_virtual_blob.result @@ -0,0 +1,21 @@ +connection node_2; +connection node_1; +CREATE TABLE t (f INT GENERATED ALWAYS AS (a+b)VIRTUAL,a INT,b INT,h BLOB); +INSERT INTO t (a,b)VALUES(0,0), (0,0), (0,0), (0,0), (0,0); +SELECT * from t; +f a b h +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +connection node_2; +SELECT * from t; +f a b h +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +0 0 0 NULL +connection node_1; +DROP TABLE t; diff --git a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf new file mode 100644 index 00000000000..889c81b4a0a --- /dev/null +++ b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.cnf @@ -0,0 +1,7 @@ +!include ../galera_2nodes.cnf + +[mysqld.1] +auto_increment_offset=1 + +[mysqld.2] +auto_increment_offset=2 diff --git a/mysql-test/suite/galera/t/galera_var_sst_auth.cnf b/mysql-test/suite/galera/t/galera_var_sst_auth.cnf index ff29db2306b..114815d446a 100644 --- a/mysql-test/suite/galera/t/galera_var_sst_auth.cnf +++ b/mysql-test/suite/galera/t/galera_var_sst_auth.cnf @@ -5,8 +5,3 @@ wsrep_sst_auth=root: [mysqld.2] wsrep_sst_auth=root: - - - - - diff --git a/mysql-test/suite/galera/t/galera_var_sst_auth.test b/mysql-test/suite/galera/t/galera_var_sst_auth.test index ad7f46620ad..ebeaddc0e63 100644 --- a/mysql-test/suite/galera/t/galera_var_sst_auth.test +++ b/mysql-test/suite/galera/t/galera_var_sst_auth.test @@ -1,6 +1,11 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + # # MDEV-10492: Assertion failure on shutdown when wsrep_sst_auth set in config # @@ -30,4 +35,5 @@ SELECT @@global.wsrep_sst_auth; --source include/wait_condition.inc SELECT @@global.wsrep_sst_auth; - +# Restore original auto_increment_offset values. +--source include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/galera/t/galera_virtual_blob.test b/mysql-test/suite/galera/t/galera_virtual_blob.test new file mode 100644 index 00000000000..a10e3025668 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_virtual_blob.test @@ -0,0 +1,10 @@ +--source include/galera_cluster.inc + +CREATE TABLE t (f INT GENERATED ALWAYS AS (a+b)VIRTUAL,a INT,b INT,h BLOB); +INSERT INTO t (a,b)VALUES(0,0), (0,0), (0,0), (0,0), (0,0); +SELECT * from t; + +--connection node_2 +SELECT * from t; +--connection node_1 +DROP TABLE t; diff --git a/mysql-test/suite/gcol/r/virtual_index_drop.result b/mysql-test/suite/gcol/r/virtual_index_drop.result new file mode 100644 index 00000000000..012e61be459 --- /dev/null +++ b/mysql-test/suite/gcol/r/virtual_index_drop.result @@ -0,0 +1,69 @@ +# +# MDEV-24971 InnoDB access freed virtual column +# after rollback of secondary index +# +CREATE TABLE t1(f1 INT, f2 INT AS (f1 + 2) VIRTUAL)ENGINE=InnoDB; +INSERT INTO t1(f1) VALUES(1), (1); +ALTER TABLE t1 ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE, LOCK=EXCLUSIVE; +ERROR 23000: Duplicate entry '3' for key 'f2' +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL, + `f2` int(11) GENERATED ALWAYS AS (`f1` + 2) VIRTUAL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT AS (f1 + 2) VIRTUAL)ENGINE=InnoDB; +INSERT INTO t1(f1) VALUES(1), (1); +ALTER TABLE t1 ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE, LOCK=SHARED; +ERROR 23000: Duplicate entry '3' for key 'f2' +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL, + `f2` int(11) GENERATED ALWAYS AS (`f1` + 2) VIRTUAL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT AS (f1) VIRTUAL)ENGINE=InnoDB; +SET DEBUG_DBUG="+d,create_index_fail"; +SET DEBUG_SYNC="innodb_inplace_alter_table_enter SIGNAL con1_go WAIT_FOR alter_signal"; +ALTER TABLE t1 ADD COLUMN f3 INT AS (f1) VIRTUAL, ADD INDEX(f2, f3); +connect con1,localhost,root,,,; +SET DEBUG_SYNC="now WAIT_FOR con1_go"; +BEGIN; +SELECT * FROM t1; +f1 f2 +SET DEBUG_SYNC="now SIGNAL alter_signal"; +connection default; +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +connection con1; +rollback; +connection default; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL, + `f2` int(11) GENERATED ALWAYS AS (`f1`) VIRTUAL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(f1 INT, f2 INT AS (f1) VIRTUAL)ENGINE=InnoDB; +SET DEBUG_DBUG="+d,create_index_fail"; +SET DEBUG_SYNC="innodb_inplace_alter_table_enter SIGNAL con1_go WAIT_FOR alter_signal"; +ALTER TABLE t1 ADD INDEX(f2); +connection con1; +SET DEBUG_SYNC="now WAIT_FOR con1_go"; +BEGIN; +INSERT INTO t1(f1) VALUES(1); +SET DEBUG_SYNC="now SIGNAL alter_signal"; +connection default; +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +connection con1; +rollback; +connection default; +disconnect con1; +DROP TABLE t1; +CREATE TABLE t1(f1 CHAR(100), f2 CHAR(100) as (f1) VIRTUAL)ENGINE=InnoDB; +ALTER TABLE t1 ADD COLUMN f3 CHAR(100) AS (f2) VIRTUAL, ADD INDEX(f3(10), f1, f3(12)); +ERROR 42S21: Duplicate column name 'f3' +DROP TABLE t1; +SET DEBUG_SYNC=RESET; diff --git a/mysql-test/suite/gcol/t/virtual_index_drop.test b/mysql-test/suite/gcol/t/virtual_index_drop.test new file mode 100644 index 00000000000..016832b9e6d --- /dev/null +++ b/mysql-test/suite/gcol/t/virtual_index_drop.test @@ -0,0 +1,71 @@ +--source include/have_innodb.inc +--source include/have_debug.inc + +--echo # +--echo # MDEV-24971 InnoDB access freed virtual column +--echo # after rollback of secondary index +--echo # + +# Exclusive lock must not defer the index removal + +CREATE TABLE t1(f1 INT, f2 INT AS (f1 + 2) VIRTUAL)ENGINE=InnoDB; +INSERT INTO t1(f1) VALUES(1), (1); +--error ER_DUP_ENTRY +ALTER TABLE t1 ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE, LOCK=EXCLUSIVE; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# If Shared lock and table doesn't have any other open handle +# then InnoDB must not defer the index removal + +CREATE TABLE t1(f1 INT, f2 INT AS (f1 + 2) VIRTUAL)ENGINE=InnoDB; +INSERT INTO t1(f1) VALUES(1), (1); +--error ER_DUP_ENTRY +ALTER TABLE t1 ADD UNIQUE INDEX(f2), ALGORITHM=INPLACE, LOCK=SHARED; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +# InnoDB should store the newly dropped virtual column into +# new_vcol_info in index when rollback of alter happens + +CREATE TABLE t1(f1 INT, f2 INT AS (f1) VIRTUAL)ENGINE=InnoDB; +SET DEBUG_DBUG="+d,create_index_fail"; +SET DEBUG_SYNC="innodb_inplace_alter_table_enter SIGNAL con1_go WAIT_FOR alter_signal"; +SEND ALTER TABLE t1 ADD COLUMN f3 INT AS (f1) VIRTUAL, ADD INDEX(f2, f3); +connect(con1,localhost,root,,,); +SET DEBUG_SYNC="now WAIT_FOR con1_go"; +BEGIN; +SELECT * FROM t1; +SET DEBUG_SYNC="now SIGNAL alter_signal"; +connection default; +--error ER_DUP_ENTRY +reap; +connection con1; +rollback; +connection default; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT, f2 INT AS (f1) VIRTUAL)ENGINE=InnoDB; +SET DEBUG_DBUG="+d,create_index_fail"; +SET DEBUG_SYNC="innodb_inplace_alter_table_enter SIGNAL con1_go WAIT_FOR alter_signal"; +send ALTER TABLE t1 ADD INDEX(f2); +connection con1; +SET DEBUG_SYNC="now WAIT_FOR con1_go"; +BEGIN; +INSERT INTO t1(f1) VALUES(1); +SET DEBUG_SYNC="now SIGNAL alter_signal"; +connection default; +--error ER_DUP_ENTRY +reap; +connection con1; +rollback; +connection default; +disconnect con1; +DROP TABLE t1; + +CREATE TABLE t1(f1 CHAR(100), f2 CHAR(100) as (f1) VIRTUAL)ENGINE=InnoDB; +--error ER_DUP_FIELDNAME +ALTER TABLE t1 ADD COLUMN f3 CHAR(100) AS (f2) VIRTUAL, ADD INDEX(f3(10), f1, f3(12)); +DROP TABLE t1; +SET DEBUG_SYNC=RESET; diff --git a/mysql-test/suite/innodb/r/innodb_buffer_pool_fail.result b/mysql-test/suite/innodb/r/innodb_buffer_pool_fail.result new file mode 100644 index 00000000000..9879ef206f2 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_buffer_pool_fail.result @@ -0,0 +1,8 @@ +call mtr.add_suppression("InnoDB: Cannot allocate memory for the buffer pool"); +call mtr.add_suppression("InnoDB: Plugin initialization aborted at srv0start.cc.*"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +# +# MDEV-25019 memory allocation failures during startup cause server failure in different, confusing ways +# +# restart: --debug_dbug=+d,ib_buf_chunk_init_fails diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index bf1204724a4..72b47bc6e20 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -368,6 +368,34 @@ SELECT * FROM t1 WHERE c<>1 ORDER BY c DESC; c d DROP TABLE t1; SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit; +# +# MDEV-24620 ASAN heap-buffer-overflow in btr_pcur_restore_position() +# +CREATE TABLE t1 (a VARCHAR(1) PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +connect stop_purge,localhost,root,,; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +ALTER TABLE t1 ADD c INT; +BEGIN; +DELETE FROM t1; +connect dml,localhost,root,,test; +SET DEBUG_SYNC='row_mysql_handle_errors SIGNAL s1 WAIT_FOR s2'; +UPDATE t1 SET c=1; +connection default; +SET DEBUG_SYNC='now WAIT_FOR s1'; +COMMIT; +connection stop_purge; +COMMIT; +disconnect stop_purge; +connection default; +InnoDB 0 transactions not purged +SET DEBUG_SYNC='now SIGNAL s2'; +connection dml; +disconnect dml; +connection default; +SET DEBUG_SYNC=RESET; +DROP TABLE t1; # End of 10.3 tests # # MDEV-17899 Assertion failures on rollback of instant ADD/DROP @@ -460,4 +488,4 @@ SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants -34 +35 diff --git a/mysql-test/suite/innodb/t/innodb_buffer_pool_fail.test b/mysql-test/suite/innodb/t/innodb_buffer_pool_fail.test new file mode 100644 index 00000000000..1d938e12e78 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_buffer_pool_fail.test @@ -0,0 +1,11 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +call mtr.add_suppression("InnoDB: Cannot allocate memory for the buffer pool"); +call mtr.add_suppression("InnoDB: Plugin initialization aborted at srv0start.cc.*"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +--echo # +--echo # MDEV-25019 memory allocation failures during startup cause server failure in different, confusing ways +--echo # +let restart_parameters=--debug_dbug="+d,ib_buf_chunk_init_fails"; +--source include/restart_mysqld.inc diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index da0692990c4..dcce4b29119 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -424,6 +424,44 @@ DROP TABLE t1; SET GLOBAL innodb_limit_optimistic_insert_debug = @saved_limit; +--echo # +--echo # MDEV-24620 ASAN heap-buffer-overflow in btr_pcur_restore_position() +--echo # + +CREATE TABLE t1 (a VARCHAR(1) PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1); +connect (stop_purge,localhost,root,,); +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +connection default; +ALTER TABLE t1 ADD c INT; +BEGIN; +DELETE FROM t1; + +connect (dml,localhost,root,,test); +SET DEBUG_SYNC='row_mysql_handle_errors SIGNAL s1 WAIT_FOR s2'; +send UPDATE t1 SET c=1; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR s1'; +COMMIT; + +connection stop_purge; +COMMIT; +disconnect stop_purge; + +connection default; +--source include/wait_all_purged.inc +SET DEBUG_SYNC='now SIGNAL s2'; + +connection dml; +reap; +disconnect dml; + +connection default; +SET DEBUG_SYNC=RESET; +DROP TABLE t1; + --echo # End of 10.3 tests --echo # diff --git a/mysql-test/suite/innodb_fts/r/fulltext.result b/mysql-test/suite/innodb_fts/r/fulltext.result index e6585723afc..b2ac4957e38 100644 --- a/mysql-test/suite/innodb_fts/r/fulltext.result +++ b/mysql-test/suite/innodb_fts/r/fulltext.result @@ -690,6 +690,19 @@ FTS_DOC_ID t 3 foo DROP TABLE t; # +# MDEV-25295 Aborted FTS_DOC_ID_INDEX considered as +# existing FTS_DOC_ID_INDEX during DDL +# +SET sql_mode=''; +CREATE TABLE t1 (FTS_DOC_ID BIGINT UNSIGNED NOT NULL,title CHAR(1),body TEXT)engine=innodb; +INSERT INTO t1 (FTS_DOC_ID,title,body)VALUES(1,0,0), (1,0,0); +CREATE FULLTEXT INDEX idx1 ON t1 (title,body); +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +CREATE FULLTEXT INDEX idx1 ON t1 (title,body); +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +DROP TABLE t1; +SET sql_mode = DEFAULT; +# # MDEV-25070 SIGSEGV in fts_create_in_mem_aux_table # CREATE TABLE t1 (a CHAR, FULLTEXT KEY(a)) ENGINE=InnoDB; @@ -703,3 +716,4 @@ t1 CREATE TABLE `t1` ( FULLTEXT KEY `a_2` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t1; +# End of 10.3 tests diff --git a/mysql-test/suite/innodb_fts/t/fulltext.test b/mysql-test/suite/innodb_fts/t/fulltext.test index fa9cace19cf..18baf56281f 100644 --- a/mysql-test/suite/innodb_fts/t/fulltext.test +++ b/mysql-test/suite/innodb_fts/t/fulltext.test @@ -719,6 +719,20 @@ while ($N) DROP TABLE t; --echo # +--echo # MDEV-25295 Aborted FTS_DOC_ID_INDEX considered as +--echo # existing FTS_DOC_ID_INDEX during DDL +--echo # +SET sql_mode=''; +CREATE TABLE t1 (FTS_DOC_ID BIGINT UNSIGNED NOT NULL,title CHAR(1),body TEXT)engine=innodb; +INSERT INTO t1 (FTS_DOC_ID,title,body)VALUES(1,0,0), (1,0,0); +--error ER_DUP_ENTRY +CREATE FULLTEXT INDEX idx1 ON t1 (title,body); +--error ER_DUP_ENTRY +CREATE FULLTEXT INDEX idx1 ON t1 (title,body); +DROP TABLE t1; +SET sql_mode = DEFAULT; + +--echo # --echo # MDEV-25070 SIGSEGV in fts_create_in_mem_aux_table --echo # CREATE TABLE t1 (a CHAR, FULLTEXT KEY(a)) ENGINE=InnoDB; @@ -728,3 +742,5 @@ ALTER TABLE t1 ADD FULLTEXT INDEX (a); SHOW CREATE TABLE t1; DROP TABLE t1; --enable_warnings + +--echo # End of 10.3 tests diff --git a/mysql-test/suite/maria/icp.result b/mysql-test/suite/maria/icp.result index 149258de918..43ec6439144 100644 --- a/mysql-test/suite/maria/icp.result +++ b/mysql-test/suite/maria/icp.result @@ -450,11 +450,11 @@ c1 INT NOT NULL, PRIMARY KEY (pk) ); INSERT INTO t1 VALUES (1,9),(2,7),(3,6),(4,3),(5,1); -EXPLAIN SELECT pk, c1 FROM t1 WHERE pk <> 3; +EXPLAIN SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 5 Using where SET SESSION optimizer_switch='index_condition_pushdown=off'; -SELECT pk, c1 FROM t1 WHERE pk <> 3; +SELECT pk, c1 FROM t1 WHERE (pk<3 or pk>3); pk c1 1 9 2 7 @@ -684,23 +684,23 @@ INSERT INTO t2 VALUES insert into t2 select seq from seq_1_to_100; SET SESSION optimizer_switch='index_condition_pushdown=off'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 SET SESSION optimizer_switch='index_condition_pushdown=on'; EXPLAIN -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL PRIMARY NULL NULL NULL # Using where; Using filesort 1 SIMPLE t2 ref a a 515 test.t1.a # Using where -SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND t1.b != 0 +SELECT t1.b, t1.c FROM t1, t2 WHERE t1.a = t2.a AND (t1.b<0 OR t1.b>0) HAVING t1.c != 5 ORDER BY t1.c; b c 1 4 diff --git a/mysql-test/suite/mariabackup/error_during_copyback.result b/mysql-test/suite/mariabackup/error_during_copyback.result new file mode 100644 index 00000000000..ba27f0f83e6 --- /dev/null +++ b/mysql-test/suite/mariabackup/error_during_copyback.result @@ -0,0 +1,10 @@ +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +# xtrabackup backup +# xtrabackup prepare +# restart server +# restart +SELECT * FROM t; +i +1 +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/error_during_copyback.test b/mysql-test/suite/mariabackup/error_during_copyback.test new file mode 100644 index 00000000000..3ec9fbfc3c3 --- /dev/null +++ b/mysql-test/suite/mariabackup/error_during_copyback.test @@ -0,0 +1,25 @@ +--source include/have_debug.inc +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +echo # xtrabackup backup; +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +echo # xtrabackup prepare; +--disable_result_log +exec $XTRABACKUP --prepare --target-dir=$targetdir; +let $_datadir= `SELECT @@datadir`; +--source include/shutdown_mysqld.inc +rmdir $_datadir; +error 1; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$_datadir --target-dir=$targetdir --dbug=+d,copy_file_error; +list_files $_datadir; +rmdir $_datadir; +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --copy-back --datadir=$_datadir --target-dir=$targetdir; +echo # restart server; +--source include/start_mysqld.inc +SELECT * FROM t; +DROP TABLE t; +rmdir $targetdir; + diff --git a/mysql-test/suite/mariabackup/innodb_force_recovery.result b/mysql-test/suite/mariabackup/innodb_force_recovery.result new file mode 100644 index 00000000000..6626bb0bc55 --- /dev/null +++ b/mysql-test/suite/mariabackup/innodb_force_recovery.result @@ -0,0 +1,26 @@ +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); +# "innodb_force_recovery=1" should be allowed with "--prepare" only (mariabackup) +FOUND 1 /should only be used with "--prepare"/ in backup.log +# "innodb_force_recovery=1" should be allowed with "--apply-log" only (innobackupex) +FOUND 1 /should only be used with "--apply-log"/ in backup.log +# "innodb_force_recovery" should be limited to "SRV_FORCE_IGNORE_CORRUPT" (mariabackup) +FOUND 1 /innodb_force_recovery = 1/ in backup.log +# "innodb_force_recovery" should be limited to "SRV_FORCE_IGNORE_CORRUPT" (innobackupex) +FOUND 1 /innodb_force_recovery = 1/ in backup.log +# "innodb_force_recovery" should be read from "backup-my.cnf" (mariabackup) +FOUND 1 /innodb_force_recovery = 1/ in backup.log +# "innodb_force_recovery=1" should be read from "backup-my.cnf" (innobackupex) +FOUND 1 /innodb_force_recovery = 1/ in backup.log +# "innodb_force_recovery" from the command line should override "backup-my.cnf" (mariabackup) +NOT FOUND /innodb_force_recovery = 1/ in backup.log +# "innodb_force_recovery" from the command line should override "backup-my.cnf" (innobackupex) +NOT FOUND /innodb_force_recovery = 1/ in backup.log +# shutdown server +# remove datadir +# xtrabackup move back +# restart +SELECT * FROM t; +i +1 +DROP TABLE t; diff --git a/mysql-test/suite/mariabackup/innodb_force_recovery.test b/mysql-test/suite/mariabackup/innodb_force_recovery.test new file mode 100644 index 00000000000..3a7b3c6106c --- /dev/null +++ b/mysql-test/suite/mariabackup/innodb_force_recovery.test @@ -0,0 +1,138 @@ +# This test checks if "innodb_force_recovery" is only allowed with "--prepare" +# (for mariabackup) and "--apply-log" (for innobackupex), and is limited to +# "SRV_FORCE_IGNORE_CORRUPT" only. + +# Setup. +--source include/have_innodb.inc + +--let targetdir=$MYSQLTEST_VARDIR/tmp/backup +--let backuplog=$MYSQLTEST_VARDIR/tmp/backup.log + +CREATE TABLE t(i INT) ENGINE INNODB; +INSERT INTO t VALUES(1); + +# Check for command line arguments. +--echo # "innodb_force_recovery=1" should be allowed with "--prepare" only (mariabackup) +--disable_result_log +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --innodb-force-recovery=1 --target-dir=$targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=should only be used with "--prepare" +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc + +--echo # "innodb_force_recovery=1" should be allowed with "--apply-log" only (innobackupex) +--disable_result_log +--error 1 +exec $XTRABACKUP --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --no-timestamp --innodb-force-recovery=1 $targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=should only be used with "--apply-log" +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc + +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +--echo # "innodb_force_recovery" should be limited to "SRV_FORCE_IGNORE_CORRUPT" (mariabackup) +--disable_result_log +exec $XTRABACKUP --prepare --innodb-force-recovery=2 --target-dir=$targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +rmdir $targetdir; + +--disable_result_log +exec $XTRABACKUP --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --no-timestamp $targetdir; +--enable_result_log +--echo # "innodb_force_recovery" should be limited to "SRV_FORCE_IGNORE_CORRUPT" (innobackupex) +--disable_result_log +exec $XTRABACKUP --innobackupex --apply-log --innodb-force-recovery=2 $targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +rmdir $targetdir; + +# Check for default file ("backup-my.cnf"). +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +perl; +my $cfg_path="$ENV{'targetdir'}/backup-my.cnf"; +open(my $fd, '>>', "$cfg_path"); +print $fd "innodb_force_recovery=1\n"; +close $fd; +EOF +--echo # "innodb_force_recovery" should be read from "backup-my.cnf" (mariabackup) +--disable_result_log +exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --prepare --export --target-dir=$targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +rmdir $targetdir; + +--disable_result_log +exec $XTRABACKUP --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --no-timestamp $targetdir; +--enable_result_log +perl; +my $cfg_path="$ENV{'targetdir'}/backup-my.cnf"; +open(my $fd, '>>', "$cfg_path"); +print $fd "innodb_force_recovery=2\n"; +close $fd; +EOF +--echo # "innodb_force_recovery=1" should be read from "backup-my.cnf" (innobackupex) +--disable_result_log +exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --export $targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +rmdir $targetdir; + +# Check for command line argument precedence. +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log +perl; +my $cfg_path="$ENV{'targetdir'}/backup-my.cnf"; +open(my $fd, '>>', "$cfg_path"); +print $fd "innodb_force_recovery=1\n"; +close $fd; +EOF +--echo # "innodb_force_recovery" from the command line should override "backup-my.cnf" (mariabackup) +--disable_result_log +exec $XTRABACKUP --defaults-file=$targetdir/backup-my.cnf --prepare --innodb-force-recovery=0 --target-dir=$targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +rmdir $targetdir; + +--disable_result_log +exec $XTRABACKUP --innobackupex --defaults-file=$MYSQLTEST_VARDIR/my.cnf --no-timestamp $targetdir; +--enable_result_log +perl; +my $cfg_path="$ENV{'targetdir'}/backup-my.cnf"; +open(my $fd, '>>', "$cfg_path"); +print $fd "innodb_force_recovery=2\n"; +close $fd; +EOF +--echo # "innodb_force_recovery" from the command line should override "backup-my.cnf" (innobackupex) +--disable_result_log +exec $XTRABACKUP --innobackupex --defaults-file=$targetdir/backup-my.cnf --apply-log --innodb-force-recovery=0 --export $targetdir >$backuplog; +--enable_result_log +--let SEARCH_PATTERN=innodb_force_recovery = 1 +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc + +--source include/restart_and_restore.inc + +# Check for restore. +SELECT * FROM t; + +# Clean-up. +DROP TABLE t; +--rmdir $targetdir +--remove_file $backuplog diff --git a/mysql-test/suite/optimizer_unfixed_bugs/r/bug42991.result b/mysql-test/suite/optimizer_unfixed_bugs/r/bug42991.result index f5554563a18..40f505d8260 100644 --- a/mysql-test/suite/optimizer_unfixed_bugs/r/bug42991.result +++ b/mysql-test/suite/optimizer_unfixed_bugs/r/bug42991.result @@ -245,7 +245,7 @@ UNLOCK TABLES; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -select * from `table5` where (col2 <= '6566-06-15' AND col24 <> 'd') group by `col83` order by `col83` desc ; +select * from `table5` where (col2 <= '6566-06-15' AND (col24 < 'd' or col24 > 'd')) group by `col83` order by `col83` desc ; col0 col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 col11 col12 col13 col14 col15 col16 col17 col18 col19 col20 col21 col22 col23 col24 col25 col26 col27 col28 col29 col30 col31 col32 col33 col34 col35 col36 col37 col38 col39 col40 col41 col42 col43 col44 col45 col46 col47 col48 col49 col50 col51 col52 col53 col54 col55 col56 col57 col58 col59 col60 col61 col62 col63 col64 col65 col66 col67 col68 col69 col70 col71 col72 col73 col74 col75 col76 col77 col78 col79 col80 col81 col82 col83 col84 col85 col86 col87 col88 col89 col90 col91 col92 col93 col94 col95 col96 col97 col98 col99 col100 col101 col102 col103 col104 col105 col106 col107 col108 col109 col110 col111 col112 col113 col114 col115 col116 col117 col118 col119 col120 col121 col122 col123 col124 col125 col126 col127 col128 col129 col130 col131 col132 col133 col134 col135 col136 col137 col138 col139 col140 col141 col142 col143 col144 col145 col146 col147 col148 col149 col150 col151 col152 col153 col154 col155 col156 col157 col158 col159 col160 col161 col162 col163 col164 col165 col166 col167 col168 col169 col170 col171 col172 col173 col174 col175 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'd' diff --git a/mysql-test/suite/optimizer_unfixed_bugs/t/bug42991.test b/mysql-test/suite/optimizer_unfixed_bugs/t/bug42991.test index d59e9e1fbeb..9e8e5c4b3cd 100644 --- a/mysql-test/suite/optimizer_unfixed_bugs/t/bug42991.test +++ b/mysql-test/suite/optimizer_unfixed_bugs/t/bug42991.test @@ -242,9 +242,9 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -#explain select * from `table5` where (col2 <= '6566-06-15' AND col24 <> 'd') group by `col83` order by `col83` desc ; +#explain select * from `table5` where (col2 <= '6566-06-15' AND (col24 < 'd' or col24 > 'd') group by `col83` order by `col83` desc ; -select * from `table5` where (col2 <= '6566-06-15' AND col24 <> 'd') group by `col83` order by `col83` desc ; +select * from `table5` where (col2 <= '6566-06-15' AND (col24 < 'd' or col24 > 'd')) group by `col83` order by `col83` desc ; drop table `table5`; SET debug_dbug= @saved_dbug; diff --git a/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test b/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test index b0588cb2d58..d3a115e986a 100644 --- a/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test +++ b/mysql-test/suite/rpl/t/rpl_row_tbl_metadata.test @@ -329,7 +329,7 @@ while($ntables) -- echo ### detect failure. Before the patch mysqlbinlog would find -- echo ### a corrupted event, thence would fail. -- let $MYSQLD_DATADIR= `SELECT @@datadir` --- exec $MYSQL_BINLOG -v --hex $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog +-- exec $MYSQL_BINLOG -v --hexdump $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug50018.binlog ## clean up ## For debugging purposes you might want not to remove these diff --git a/mysql-test/suite/versioning/r/alter.result b/mysql-test/suite/versioning/r/alter.result index 3cdba78b973..d0aa49f2fde 100644 --- a/mysql-test/suite/versioning/r/alter.result +++ b/mysql-test/suite/versioning/r/alter.result @@ -80,7 +80,7 @@ t CREATE TABLE `t` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 alter table t add column trx_start timestamp(6) as row start; -ERROR HY000: Duplicate ROW START column `trx_start` +ERROR HY000: Table `t` is not system-versioned alter table t add system versioning; show create table t; Table Create Table @@ -697,6 +697,55 @@ set statement system_versioning_alter_history=keep for alter table t1 drop system versioning, modify column a tinyint; drop table t1; # +# MDEV-24690 Dropping primary key column from versioned table always fails with 1072 +# +create table t1 (a int, b int primary key) with system versioning; +alter table t1 drop column b; +create or replace table t1 ( +a int, b int primary key, +row_start timestamp(6) as row start, +row_end timestamp(6) as row end, +period for system_time(row_start, row_end) +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) NOT NULL, + `row_start` timestamp(6) GENERATED ALWAYS AS ROW START, + `row_end` timestamp(6) GENERATED ALWAYS AS ROW END, + PRIMARY KEY (`b`,`row_end`), + PERIOD FOR SYSTEM_TIME (`row_start`, `row_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t1 drop column b; +ERROR 42000: Key column 'b' doesn't exist in table +create or replace table t1 ( +a int, b int primary key, +row_start timestamp(6) as row start invisible, +row_end timestamp(6) as row end invisible, +period for system_time(row_start, row_end) +) with system versioning; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) NOT NULL, + `row_start` timestamp(6) GENERATED ALWAYS AS ROW START INVISIBLE, + `row_end` timestamp(6) GENERATED ALWAYS AS ROW END INVISIBLE, + PRIMARY KEY (`b`,`row_end`), + PERIOD FOR SYSTEM_TIME (`row_start`, `row_end`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 WITH SYSTEM VERSIONING +alter table t1 drop column b; +ERROR 42000: Key column 'b' doesn't exist in table +drop table t1; +# +# MDEV-25172 Wrong error message for ADD COLUMN .. AS ROW START +# +create or replace table t1 (x int); +alter table t1 add column y timestamp(6) as row start; +ERROR HY000: Table `t1` is not system-versioned +drop table t1; +# # MDEV-21941 RENAME doesn't work for system time or period fields # create or replace table t1 (a int) with system versioning; diff --git a/mysql-test/suite/versioning/r/auto_increment.result b/mysql-test/suite/versioning/r/autoinc.result index 8ff1bed8fe3..e785c5d300e 100644 --- a/mysql-test/suite/versioning/r/auto_increment.result +++ b/mysql-test/suite/versioning/r/autoinc.result @@ -63,3 +63,13 @@ A x y x y 1 7 17 7 17 drop table t1; drop table t2; +# +# MDEV-22562 Assertion `next_insert_id == 0' upon UPDATE on system-versioned table +# +create table t1 (pk integer auto_increment primary key) engine=myisam with system versioning; +insert delayed into t1 (pk) values (1); +lock tables t1 write; +update t1 set pk= 0; +update t1 set pk= 0; +unlock tables; +drop table t1; diff --git a/mysql-test/suite/versioning/t/alter.test b/mysql-test/suite/versioning/t/alter.test index 9e0ed7cabb9..786627da35e 100644 --- a/mysql-test/suite/versioning/t/alter.test +++ b/mysql-test/suite/versioning/t/alter.test @@ -68,7 +68,7 @@ select row_start from t; alter table t drop system versioning; show create table t; ---error ER_VERS_DUPLICATE_ROW_START_END +--error ER_VERS_NOT_VERSIONED alter table t add column trx_start timestamp(6) as row start; alter table t add system versioning; @@ -595,6 +595,44 @@ alter table t1 drop system versioning, modify column a tinyint; drop table t1; --echo # +--echo # MDEV-24690 Dropping primary key column from versioned table always fails with 1072 +--echo # +create table t1 (a int, b int primary key) with system versioning; +alter table t1 drop column b; + +create or replace table t1 ( + a int, b int primary key, + row_start timestamp(6) as row start, + row_end timestamp(6) as row end, + period for system_time(row_start, row_end) +) with system versioning; +show create table t1; +--error ER_KEY_COLUMN_DOES_NOT_EXITS +alter table t1 drop column b; + +create or replace table t1 ( +a int, b int primary key, + row_start timestamp(6) as row start invisible, + row_end timestamp(6) as row end invisible, + period for system_time(row_start, row_end) +) with system versioning; +show create table t1; +--error ER_KEY_COLUMN_DOES_NOT_EXITS +alter table t1 drop column b; + +# cleanup +drop table t1; + +--echo # +--echo # MDEV-25172 Wrong error message for ADD COLUMN .. AS ROW START +--echo # +create or replace table t1 (x int); +--error ER_VERS_NOT_VERSIONED +alter table t1 add column y timestamp(6) as row start; +# cleanup +drop table t1; + +--echo # --echo # MDEV-21941 RENAME doesn't work for system time or period fields --echo # create or replace table t1 (a int) with system versioning; diff --git a/mysql-test/suite/versioning/t/auto_increment.test b/mysql-test/suite/versioning/t/autoinc.test index 804c0424179..7c87c17301a 100644 --- a/mysql-test/suite/versioning/t/auto_increment.test +++ b/mysql-test/suite/versioning/t/autoinc.test @@ -47,4 +47,17 @@ select t1.x = t2.x and t1.y = t2.y as A, t1.x, t1.y, t2.x, t2.y from t1 inner jo drop table t1; drop table t2; +--echo # +--echo # MDEV-22562 Assertion `next_insert_id == 0' upon UPDATE on system-versioned table +--echo # +create table t1 (pk integer auto_increment primary key) engine=myisam with system versioning; +insert delayed into t1 (pk) values (1); +lock tables t1 write; +update t1 set pk= 0; +update t1 set pk= 0; +unlock tables; + +# cleanup +drop table t1; + -- source suite/versioning/common_finish.inc diff --git a/plugin/userstat/index_stats.cc b/plugin/userstat/index_stats.cc index 3ad5ef2e1ad..97305e894bb 100644 --- a/plugin/userstat/index_stats.cc +++ b/plugin/userstat/index_stats.cc @@ -32,7 +32,7 @@ static int index_stats_fill(THD *thd, TABLE_LIST *tables, COND *cond) tmp_table.grant.privilege= NO_ACL; if (check_access(thd, SELECT_ACL, tmp_table.db.str, &tmp_table.grant.privilege, NULL, 0, 1) || - check_grant(thd, SELECT_ACL, &tmp_table, 1, UINT_MAX, 1)) + check_grant(thd, SELECT_ACL, &tmp_table, 1, 1, 1)) continue; index_name= tmp_table.table_name.str + tmp_table.table_name.length + 1; diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index bbd1bafbd41..2359cbc0ced 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -1,6 +1,6 @@ #!/bin/bash -ue # Copyright (C) 2013 Percona Inc -# Copyright (C) 2017-2020 MariaDB +# Copyright (C) 2017-2021 MariaDB # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -851,7 +851,7 @@ then -z $(parse_cnf --mysqld tmpdir "") && \ -z $(parse_cnf xtrabackup tmpdir "") ]]; then xtmpdir=$(mktemp -d) - tmpopts=" --tmpdir=$xtmpdir" + tmpopts="--tmpdir=$xtmpdir" wsrep_log_info "Using $xtmpdir as xtrabackup temporary directory" fi diff --git a/sql/handler.cc b/sql/handler.cc index 7e3b46cab04..c6031e252a6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3546,25 +3546,27 @@ int handler::update_auto_increment() DBUG_RETURN(0); } - // ALTER TABLE ... ADD COLUMN ... AUTO_INCREMENT - if (thd->lex->sql_command == SQLCOM_ALTER_TABLE) + if (table->versioned()) { - if (table->versioned()) + Field *end= table->vers_end_field(); + DBUG_ASSERT(end); + bitmap_set_bit(table->read_set, end->field_index); + if (!end->is_max()) { - Field *end= table->vers_end_field(); - DBUG_ASSERT(end); - bitmap_set_bit(table->read_set, end->field_index); - if (!end->is_max()) + if (thd->lex->sql_command == SQLCOM_ALTER_TABLE) { if (!table->next_number_field->real_maybe_null()) DBUG_RETURN(HA_ERR_UNSUPPORTED); table->next_number_field->set_null(); - DBUG_RETURN(0); } + DBUG_RETURN(0); } - table->next_number_field->set_notnull(); } + // ALTER TABLE ... ADD COLUMN ... AUTO_INCREMENT + if (thd->lex->sql_command == SQLCOM_ALTER_TABLE) + table->next_number_field->set_notnull(); + if ((nr= next_insert_id) >= auto_inc_interval_for_cur_row.maximum()) { /* next_insert_id is beyond what is reserved, so we reserve more. */ @@ -8021,6 +8023,11 @@ bool Vers_parse_info::fix_alter_info(THD *thd, Alter_info *alter_info, { if (f->flags & VERS_SYSTEM_FIELD) { + if (!table->versioned()) + { + my_error(ER_VERS_NOT_VERSIONED, MYF(0), table->s->table_name.str); + return true; + } my_error(ER_VERS_DUPLICATE_ROW_START_END, MYF(0), f->flags & VERS_SYS_START_FLAG ? "START" : "END", f->field_name.str); return true; diff --git a/sql/item.cc b/sql/item.cc index 3dbe3badadf..1d13fee58ed 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5051,13 +5051,19 @@ bool Item_ref_null_helper::get_date(THD *thd, MYSQL_TIME *ltime, @param resolved_item item which was resolved in outer SELECT(for warning) @param mark_item item which should be marked (can be differ in case of substitution) + @param suppress_warning_output flag specifying whether to suppress output of + a warning message */ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, Item_ident *resolved_item, - Item_ident *mark_item) + Item_ident *mark_item, + bool suppress_warning_output) { DBUG_ENTER("mark_as_dependent"); + DBUG_PRINT("info", ("current select: %d (%p) last: %d (%p)", + current->select_number, current, + (last ? last->select_number : 0), last)); /* store pointer on SELECT_LEX from which item is dependent */ if (mark_item && mark_item->can_be_depended) @@ -5068,7 +5074,7 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, if (current->mark_as_dependent(thd, last, /** resolved_item psergey-thu **/ mark_item)) DBUG_RETURN(TRUE); - if (thd->lex->describe & DESCRIBE_EXTENDED) + if ((thd->lex->describe & DESCRIBE_EXTENDED) && !suppress_warning_output) { const char *db_name= (resolved_item->db_name.str ? resolved_item->db_name.str : ""); @@ -5097,6 +5103,8 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, @param found_item Item which was found during resolving (if resolved identifier belongs to VIEW) @param resolved_item Identifier which was resolved + @param suppress_warning_output flag specifying whether to suppress output of + a warning message @note We have to mark all items between current_sel (including) and @@ -5109,7 +5117,8 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, void mark_select_range_as_dependent(THD *thd, SELECT_LEX *last_select, SELECT_LEX *current_sel, Field *found_field, Item *found_item, - Item_ident *resolved_item) + Item_ident *resolved_item, + bool suppress_warning_output) { /* Go from current SELECT to SELECT where field was resolved (it @@ -5144,7 +5153,7 @@ void mark_select_range_as_dependent(THD *thd, SELECT_LEX *last_select, found_field->table->map; prev_subselect_item->const_item_cache= 0; mark_as_dependent(thd, last_select, current_sel, resolved_item, - dependent); + dependent, suppress_warning_output); } @@ -5610,7 +5619,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) context->select_lex, this, ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? - (Item_ident*) (*reference) : 0)); + (Item_ident*) (*reference) : 0), false); return 0; } } @@ -5622,7 +5631,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) context->select_lex, this, ((ref_type == REF_ITEM || ref_type == FIELD_ITEM) ? (Item_ident*) (*reference) : - 0)); + 0), false); if (thd->lex->in_sum_func && thd->lex->in_sum_func->nest_level >= select->nest_level) { @@ -5736,7 +5745,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, rf, - rf); + rf, false); return 0; } @@ -5749,7 +5758,7 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) set_max_sum_func_level(thd, select); mark_as_dependent(thd, last_checked_context->select_lex, context->select_lex, - this, (Item_ident*)*reference); + this, (Item_ident*)*reference, false); if (last_checked_context->select_lex->having_fix_field) { Item_ref *rf; @@ -7723,7 +7732,7 @@ public: if (tbl->table == item->field->table) { if (sel != current_select) - mark_as_dependent(thd, sel, current_select, item, item); + mark_as_dependent(thd, sel, current_select, item, item, false); return; } } @@ -7919,7 +7928,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) ((refer_type == REF_ITEM || refer_type == FIELD_ITEM) ? (Item_ident*) (*reference) : - 0)); + 0), false); /* view reference found, we substituted it instead of this Item, so can quit @@ -7969,7 +7978,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) goto error; thd->change_item_tree(reference, fld); mark_as_dependent(thd, last_checked_context->select_lex, - current_sel, fld, fld); + current_sel, fld, fld, false); /* A reference is resolved to a nest level that's outer or the same as the nest level of the enclosing set function : adjust the value of @@ -7992,7 +8001,7 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) /* Should be checked in resolve_ref_in_select_and_group(). */ DBUG_ASSERT(*ref && (*ref)->is_fixed()); mark_as_dependent(thd, last_checked_context->select_lex, - context->select_lex, this, this); + context->select_lex, this, this, false); /* A reference is resolved to a nest level that's outer or the same as the nest level of the enclosing set function : adjust the value of diff --git a/sql/item.h b/sql/item.h index a1c288ab1f0..9b7f2cc68e9 100644 --- a/sql/item.h +++ b/sql/item.h @@ -7394,7 +7394,8 @@ void mark_select_range_as_dependent(THD *thd, st_select_lex *last_select, st_select_lex *current_sel, Field *found_field, Item *found_item, - Item_ident *resolved_item); + Item_ident *resolved_item, + bool suppress_warning_output); extern Cached_item *new_Cached_item(THD *thd, Item *item, bool pass_through_ref); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 46412fe8ad6..aa7269ab95a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -838,11 +838,7 @@ class Item_func_ne :public Item_bool_rowready_func2 { protected: SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param, - Field *field, Item *value) - { - DBUG_ENTER("Item_func_ne::get_func_mm_tree"); - DBUG_RETURN(get_ne_mm_tree(param, field, value, value)); - } + Field *field, Item *value); public: Item_func_ne(THD *thd, Item *a, Item *b): Item_bool_rowready_func2(thd, a, b) {} diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 1089249c048..1f1c3454a55 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -291,7 +291,8 @@ public: friend bool Item_ref::fix_fields(THD *, Item **); friend void mark_select_range_as_dependent(THD*, st_select_lex*, st_select_lex*, - Field*, Item*, Item_ident*); + Field*, Item*, Item_ident*, + bool); friend bool convert_join_subqueries_to_semijoins(JOIN *join); }; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f1657b51bf3..9ec8781bc30 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -461,6 +461,7 @@ void print_range_for_non_indexed_field(String *out, Field *field, static void print_min_range_operator(String *out, const ha_rkey_function flag); static void print_max_range_operator(String *out, const ha_rkey_function flag); +static bool is_field_an_unique_index(RANGE_OPT_PARAM *param, Field *field); /* SEL_IMERGE is a list of possible ways to do index merge, i.e. it is @@ -7721,6 +7722,21 @@ SEL_TREE *Item_bool_func::get_ne_mm_tree(RANGE_OPT_PARAM *param, } +SEL_TREE *Item_func_ne::get_func_mm_tree(RANGE_OPT_PARAM *param, + Field *field, Item *value) +{ + DBUG_ENTER("Item_func_ne::get_func_mm_tree"); + /* + If this condition is a "col1<>...", where there is a UNIQUE KEY(col1), + do not construct a SEL_TREE from it. A condition that excludes just one + row in the table is not selective (unless there are only a few rows) + */ + if (is_field_an_unique_index(param, field)) + DBUG_RETURN(NULL); + DBUG_RETURN(get_ne_mm_tree(param, field, value, value)); +} + + SEL_TREE *Item_func_between::get_func_mm_tree(RANGE_OPT_PARAM *param, Field *field, Item *value) { @@ -7819,28 +7835,16 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param, DBUG_RETURN(0); /* - If this is "unique_key NOT IN (...)", do not consider it sargable (for - any index, not just the unique one). The logic is as follows: + if this is a "col1 NOT IN (...)", and there is a UNIQUE KEY(col1), do + not constuct a SEL_TREE from it. The rationale is as follows: - if there are only a few constants, this condition is not selective (unless the table is also very small in which case we won't gain anything) - - If there are a lot of constants, the overhead of building and + - if there are a lot of constants, the overhead of building and processing enormous range list is not worth it. */ - if (param->using_real_indexes) - { - key_map::Iterator it(field->key_start); - uint key_no; - while ((key_no= it++) != key_map::Iterator::BITMAP_END) - { - KEY *key_info= &field->table->key_info[key_no]; - if (key_info->user_defined_key_parts == 1 && - (key_info->flags & HA_NOSAME)) - { - DBUG_RETURN(0); - } - } - } + if (is_field_an_unique_index(param, field)) + DBUG_RETURN(0); /* Get a SEL_TREE for "(-inf|NULL) < X < c_0" interval. */ uint i=0; @@ -8540,6 +8544,38 @@ SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) } +/* + @brief + Check if there is an one-segment unique key that matches the field exactly + + @detail + In the future we could also add "almost unique" indexes where any value is + present only in a few rows (but necessarily exactly one row) +*/ +static bool is_field_an_unique_index(RANGE_OPT_PARAM *param, Field *field) +{ + DBUG_ENTER("is_field_an_unique_index"); + + // The check for using_real_indexes is there because of the heuristics + // this function is used for. + if (param->using_real_indexes) + { + key_map::Iterator it(field->key_start); + uint key_no; + while ((key_no= it++) != key_map::Iterator::BITMAP_END) + { + KEY *key_info= &field->table->key_info[key_no]; + if (key_info->user_defined_key_parts == 1 && + (key_info->flags & HA_NOSAME)) + { + DBUG_RETURN(true); + } + } + } + DBUG_RETURN(false); +} + + SEL_TREE * Item_bool_func::get_mm_parts(RANGE_OPT_PARAM *param, Field *field, Item_func::Functype type, Item *value) diff --git a/sql/spatial.cc b/sql/spatial.cc index 7a3286dae1c..13fff34df21 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2011, 2020, MariaDB Corporation. + Copyright (c) 2011, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1075,7 +1075,7 @@ double Gis_point::calculate_haversine(const Geometry *g, int *error) { DBUG_ASSERT(sphere_radius > 0); - double x1r, x2r, y1r, y2r, dlong, dlat, res; + double x1r, x2r, y1r, y2r; // This check is done only for optimization purposes where we know it will // be one and only one point in Multipoint @@ -1092,31 +1092,39 @@ double Gis_point::calculate_haversine(const Geometry *g, Geometry *gg= Geometry::construct(&gbuff, point_temp, point_size-1); DBUG_ASSERT(gg); if (static_cast<Gis_point *>(gg)->get_xy_radian(&x2r, &y2r)) + { DBUG_ASSERT(0); + return -1; + } } else { if (static_cast<const Gis_point *>(g)->get_xy_radian(&x2r, &y2r)) + { DBUG_ASSERT(0); + return -1; + } } if (this->get_xy_radian(&x1r, &y1r)) + { DBUG_ASSERT(0); + return -1; + } // Check boundary conditions: longitude[-180,180] if (!((x2r >= -M_PI && x2r <= M_PI) && (x1r >= -M_PI && x1r <= M_PI))) { *error=1; return -1; } - // Check boundary conditions: lattitude[-90,90] + // Check boundary conditions: latitude[-90,90] if (!((y2r >= -M_PI/2 && y2r <= M_PI/2) && (y1r >= -M_PI/2 && y1r <= M_PI/2))) { *error=-1; return -1; } - dlat= sin((y2r - y1r)/2)*sin((y2r - y1r)/2); - dlong= sin((x2r - x1r)/2)*sin((x2r - x1r)/2); - res= 2*sphere_radius*asin((sqrt(dlat + cos(y1r)*cos(y2r)*dlong))); - return res; + double dlat= sin((y2r - y1r)/2)*sin((y2r - y1r)/2); + double dlong= sin((x2r - x1r)/2)*sin((x2r - x1r)/2); + return 2*sphere_radius*asin((sqrt(dlat + cos(y1r)*cos(y2r)*dlong))); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 87970ee11b4..85318c60ec3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -6407,7 +6407,7 @@ find_field_in_tables(THD *thd, Item_ident *item, if (!all_merged && current_sel != last_select) { mark_select_range_as_dependent(thd, last_select, current_sel, - found, *ref, item); + found, *ref, item, true); } } return found; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 02652dd095c..ce5f78b84ad 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3344,7 +3344,7 @@ void st_select_lex_unit::exclude_tree() */ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, - Item *dependency) + Item_ident *dependency) { DBUG_ASSERT(this != last); @@ -3352,10 +3352,14 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, /* Mark all selects from resolved to 1 before select where was found table as depended (of select where was found table) + + We move by name resolution context, bacause during merge can some select + be excleded from SELECT tree */ - SELECT_LEX *s= this; + Name_resolution_context *c= &this->context; do { + SELECT_LEX *s= c->select_lex; if (!(s->uncacheable & UNCACHEABLE_DEPENDENT_GENERATED)) { // Select is dependent of outer select @@ -3377,7 +3381,7 @@ bool st_select_lex::mark_as_dependent(THD *thd, st_select_lex *last, if (subquery_expr && subquery_expr->mark_as_dependent(thd, last, dependency)) return TRUE; - } while ((s= s->outer_select()) != last && s != 0); + } while ((c= c->outer_context) != NULL && (c->select_lex != last)); is_correlated= TRUE; master_unit()->item->is_correlated= TRUE; return FALSE; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index c475c6d3385..846d6b9a822 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1378,7 +1378,8 @@ public: } inline bool is_subquery_function() { return master_unit()->item != 0; } - bool mark_as_dependent(THD *thd, st_select_lex *last, Item *dependency); + bool mark_as_dependent(THD *thd, st_select_lex *last, + Item_ident *dependency); void set_braces(bool value) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e8aa92aa52c..0e2b80beb78 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1663,7 +1663,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (unlikely(thd->security_ctx->password_expired && command != COM_QUERY && command != COM_PING && - command != COM_QUIT)) + command != COM_QUIT && + command != COM_STMT_PREPARE && + command != COM_STMT_EXECUTE)) { my_error(ER_MUST_CHANGE_PASSWORD, MYF(0)); goto dispatch_end; @@ -3530,7 +3532,10 @@ mysql_execute_command(THD *thd) first_table->for_insert_data); if (thd->security_ctx->password_expired && - lex->sql_command != SQLCOM_SET_OPTION) + lex->sql_command != SQLCOM_SET_OPTION && + lex->sql_command != SQLCOM_PREPARE && + lex->sql_command != SQLCOM_EXECUTE && + lex->sql_command != SQLCOM_DEALLOCATE_PREPARE) { my_error(ER_MUST_CHANGE_PASSWORD, MYF(0)); DBUG_RETURN(1); @@ -3822,7 +3827,8 @@ mysql_execute_command(THD *thd) thd->transaction->stmt.mark_trans_did_ddl(); #ifdef WITH_WSREP /* Clean up the previous transaction on implicit commit */ - if (wsrep_thd_is_local(thd) && wsrep_after_statement(thd)) + if (WSREP_NNULL(thd) && wsrep_thd_is_local(thd) && + wsrep_after_statement(thd)) { goto error; } @@ -3896,7 +3902,7 @@ mysql_execute_command(THD *thd) Do not start transaction for stored procedures, it will be handled internally in SP processing. */ - if (WSREP(thd) && + if (WSREP_NNULL(thd) && wsrep_thd_is_local(thd) && lex->sql_command != SQLCOM_BEGIN && lex->sql_command != SQLCOM_CALL && diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 314966fbf00..3f28f818acc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4238,6 +4238,15 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) thd->is_error() || init_param_array(this)); + if (thd->security_ctx->password_expired && + lex->sql_command != SQLCOM_SET_OPTION) + { + thd->restore_backup_statement(this, &stmt_backup); + thd->restore_active_arena(this, &stmt_backup); + thd->stmt_arena= old_stmt_arena; + my_error(ER_MUST_CHANGE_PASSWORD, MYF(0)); + DBUG_RETURN(true); + } lex->set_trg_event_type_for_tables(); /* diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 27092f2b663..e87c1a989cd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13638,18 +13638,21 @@ ha_rows JOIN_TAB::get_examined_rows() bool JOIN_TAB::preread_init() { TABLE_LIST *derived= table->pos_in_table_list; + DBUG_ENTER("JOIN_TAB::preread_init"); + if (!derived || !derived->is_materialized_derived()) { preread_init_done= TRUE; - return FALSE; + DBUG_RETURN(FALSE); } /* Materialize derived table/view. */ if ((!derived->get_unit()->executed || derived->is_recursive_with_table() || derived->get_unit()->uncacheable) && - mysql_handle_single_derived(join->thd->lex, derived, DT_CREATE | DT_FILL)) - return TRUE; + mysql_handle_single_derived(join->thd->lex, + derived, DT_CREATE | DT_FILL)) + DBUG_RETURN(TRUE); if (!(derived->get_unit()->uncacheable & UNCACHEABLE_DEPENDENT) || derived->is_nonrecursive_derived_with_rec_ref()) @@ -13667,9 +13670,9 @@ bool JOIN_TAB::preread_init() /* init ftfuns for just initialized derived table */ if (table->fulltext_searched) if (init_ftfuncs(join->thd, join->select_lex, MY_TEST(join->order))) - return TRUE; + DBUG_RETURN(TRUE); - return FALSE; + DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f1e1b6517d8..99070bcd89c 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -8833,6 +8833,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, long_hash_key= true; } const char *dropped_key_part= NULL; + bool user_keyparts= false; // some user-defined keyparts left KEY_PART_INFO *key_part= key_info->key_part; key_parts.empty(); uint key_parts_nr= key_info->user_defined_key_parts; @@ -8912,6 +8913,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key_parts.push_back(new (thd->mem_root) Key_part_spec(&cfield->field_name, key_part_length, true), thd->mem_root); + if (cfield->invisible < INVISIBLE_SYSTEM) + user_keyparts= true; } if (table->s->tmp_table == NO_TMP_TABLE) { @@ -8957,7 +8960,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key_type= Key::PRIMARY; else key_type= Key::UNIQUE; - if (dropped_key_part) + if (dropped_key_part && user_keyparts) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), dropped_key_part); if (long_hash_key) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 35ceeeff43a..79b1166338a 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2011, 2020, MariaDB + Copyright (c) 2011, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2490,10 +2490,10 @@ int multi_update::send_data(List<Item> ¬_used_values) { TABLE_LIST *cur_table; DBUG_ENTER("multi_update::send_data"); - int error= 0; for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) { + int error= 0; TABLE *table= cur_table->table; uint offset= cur_table->shared; /* @@ -2563,21 +2563,7 @@ int multi_update::send_data(List<Item> ¬_used_values) updated--; if (!ignore || table->file->is_fatal_error(error, HA_CHECK_ALL)) - { -error: - /* - If (ignore && error == is ignorable) we don't have to - do anything; otherwise... - */ - myf flags= 0; - - if (table->file->is_fatal_error(error, HA_CHECK_ALL)) - flags|= ME_FATAL; /* Other handler errors are fatal */ - - prepare_record_for_error_message(error, table); - table->file->print_error(error,MYF(flags)); - DBUG_RETURN(1); - } + goto error; } else { @@ -2653,7 +2639,22 @@ error: } } } - } + continue; +error: + DBUG_ASSERT(error > 0); + /* + If (ignore && error == is ignorable) we don't have to + do anything; otherwise... + */ + myf flags= 0; + + if (table->file->is_fatal_error(error, HA_CHECK_ALL)) + flags|= ME_FATAL; /* Other handler errors are fatal */ + + prepare_record_for_error_message(error, table); + table->file->print_error(error,MYF(flags)); + DBUG_RETURN(1); + } // for (cur_table) DBUG_RETURN(0); } diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index 1f6576093cb..942363d9886 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -439,8 +439,10 @@ static inline void wsrep_after_apply(THD* thd) static inline void wsrep_open(THD* thd) { DBUG_ENTER("wsrep_open"); - if (WSREP_PROVIDER_EXISTS) + if (WSREP_ON_) { + /* WSREP_PROVIDER_EXISTS_ cannot be set if WSREP_ON_ is not set */ + DBUG_ASSERT(WSREP_PROVIDER_EXISTS_); thd->wsrep_cs().open(wsrep::client_id(thd->thread_id)); thd->wsrep_cs().debug_log_level(wsrep_debug); if (!thd->wsrep_applier && thd->variables.wsrep_trx_fragment_size) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index a6a8d62ade6..de87ad02e68 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -848,7 +848,7 @@ btr_page_get_father_node_ptr_func( node_ptr = btr_cur_get_rec(cursor); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); if (btr_node_ptr_get_child_page_no(node_ptr, offsets) != page_no) { @@ -865,10 +865,11 @@ btr_page_get_father_node_ptr_func( print_rec = page_rec_get_next( page_get_infimum_rec(page_align(user_rec))); offsets = rec_get_offsets(print_rec, index, offsets, - page_rec_is_leaf(user_rec), + page_rec_is_leaf(user_rec) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); page_rec_print(print_rec, offsets); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); page_rec_print(node_ptr, offsets); @@ -2214,7 +2215,9 @@ btr_page_get_split_rec( incl_data += insert_size; } else { offsets = rec_get_offsets(rec, cursor->index, offsets, - page_is_leaf(page), + page_is_leaf(page) + ? cursor->index->n_core_fields + : 0, ULINT_UNDEFINED, &heap); incl_data += rec_offs_size(offsets); } @@ -2323,7 +2326,9 @@ btr_page_insert_fits( space after rec is removed from page. */ *offsets = rec_get_offsets(rec, cursor->index, *offsets, - page_is_leaf(page), + page_is_leaf(page) + ? cursor->index->n_core_fields + : 0, ULINT_UNDEFINED, heap); total_data -= rec_offs_size(*offsets); @@ -2583,7 +2588,8 @@ btr_page_tuple_smaller( first_rec = page_cur_get_rec(&pcur); *offsets = rec_get_offsets( - first_rec, cursor->index, *offsets, page_is_leaf(block->frame), + first_rec, cursor->index, *offsets, + page_is_leaf(block->frame) ? cursor->index->n_core_fields : 0, n_uniq, heap); return(cmp_dtuple_rec(tuple, first_rec, *offsets) < 0); @@ -2872,7 +2878,9 @@ func_start: first_rec = move_limit = split_rec; *offsets = rec_get_offsets(split_rec, cursor->index, *offsets, - page_is_leaf(page), n_uniq, heap); + page_is_leaf(page) + ? cursor->index->n_core_fields : 0, + n_uniq, heap); insert_left = !tuple || cmp_dtuple_rec(tuple, split_rec, *offsets) < 0; @@ -3518,7 +3526,7 @@ retry: rec_offs* offsets2 = NULL; /* For rtree, we need to update father's mbr. */ - if (dict_index_is_spatial(index)) { + if (index->is_spatial()) { /* We only support merge pages with the same parent page */ if (!rtr_check_same_block( @@ -3536,7 +3544,8 @@ retry: offsets2 = rec_get_offsets( btr_cur_get_rec(&cursor2), index, NULL, - page_is_leaf(cursor2.page_cur.block->frame), + page_is_leaf(cursor2.page_cur.block->frame) + ? index->n_fields : 0, ULINT_UNDEFINED, &heap); /* Check if parent entry needs to be updated */ @@ -3706,13 +3715,14 @@ retry: #endif /* UNIV_DEBUG */ /* For rtree, we need to update father's mbr. */ - if (dict_index_is_spatial(index)) { + if (index->is_spatial()) { rec_offs* offsets2; ulint rec_info; offsets2 = rec_get_offsets( btr_cur_get_rec(&cursor2), index, NULL, - page_is_leaf(cursor2.page_cur.block->frame), + page_is_leaf(cursor2.page_cur.block->frame) + ? index->n_fields : 0, ULINT_UNDEFINED, &heap); ut_ad(btr_node_ptr_get_child_page_no( @@ -3927,16 +3937,16 @@ btr_discard_only_page_on_level( } #endif /* UNIV_BTR_DEBUG */ - mem_heap_t* heap = NULL; - const rec_t* rec = NULL; - rec_offs* offsets = NULL; - + mem_heap_t* heap = nullptr; + const rec_t* rec = nullptr; + rec_offs* offsets = nullptr; if (index->table->instant || index->must_avoid_clear_instant_add()) { if (!rec_is_metadata(r, *index)) { } else if (!index->table->instant || rec_is_alter_metadata(r, *index)) { heap = mem_heap_create(srv_page_size); - offsets = rec_get_offsets(r, index, NULL, true, + offsets = rec_get_offsets(r, index, nullptr, + index->n_core_fields, ULINT_UNDEFINED, &heap); rec = rec_copy(mem_heap_alloc(heap, rec_offs_size(offsets)), @@ -4193,7 +4203,7 @@ btr_print_recursive( node_ptr = page_cur_get_rec(&cursor); *offsets = rec_get_offsets( - node_ptr, index, *offsets, false, + node_ptr, index, *offsets, 0, ULINT_UNDEFINED, heap); btr_print_recursive(index, btr_node_ptr_get_child(node_ptr, @@ -4342,7 +4352,9 @@ btr_index_rec_validate( page = page_align(rec); - if (dict_index_is_ibuf(index)) { + ut_ad(index->n_core_fields); + + if (index->is_ibuf()) { /* The insert buffer index tree can contain records from any other index: we cannot check the number of fields or their length */ @@ -4406,7 +4418,8 @@ n_field_mismatch: } } - offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page), + offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); const dict_field_t* field = index->fields; ut_ad(rec_offs_n_fields(offsets) @@ -4659,7 +4672,7 @@ btr_validate_level( page_cur_move_to_next(&cursor); node_ptr = page_cur_get_rec(&cursor); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); savepoint2 = mtr_set_savepoint(&mtr); @@ -4778,10 +4791,12 @@ loop: right_rec = page_rec_get_next(page_get_infimum_rec( right_page)); offsets = rec_get_offsets(rec, index, offsets, - page_is_leaf(page), + page_is_leaf(page) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); offsets2 = rec_get_offsets(right_rec, index, offsets2, - page_is_leaf(right_page), + page_is_leaf(right_page) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); /* For spatial index, we cannot guarantee the key ordering diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 6e8b88172e8..9004064a1b9 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2014, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -170,7 +170,8 @@ inline void PageBulk::insertPage(rec_t *rec, rec_offs *offsets) (fmt == REDUNDANT ? PAGE_OLD_INFIMUM : PAGE_NEW_INFIMUM)) { const rec_t *old_rec = m_cur_rec; - rec_offs *old_offsets= rec_get_offsets(old_rec, m_index, nullptr, is_leaf, + rec_offs *old_offsets= rec_get_offsets(old_rec, m_index, nullptr, is_leaf + ? m_index->n_core_fields : 0, ULINT_UNDEFINED, &m_heap); ut_ad(cmp_rec_rec(rec, old_rec, offsets, old_offsets, m_index) > 0); } @@ -604,6 +605,7 @@ PageBulk::getSplitRec() ut_ad(m_page_zip != NULL); ut_ad(m_rec_no >= 2); + ut_ad(!m_index->is_instant()); ut_ad(page_get_free_space_of_empty(m_is_comp) > m_free_space); total_used_size = page_get_free_space_of_empty(m_is_comp) @@ -613,13 +615,13 @@ PageBulk::getSplitRec() n_recs = 0; offsets = NULL; rec = page_get_infimum_rec(m_page); + const ulint n_core = page_is_leaf(m_page) ? m_index->n_core_fields : 0; do { rec = page_rec_get_next(rec); ut_ad(page_rec_is_user_rec(rec)); - offsets = rec_get_offsets(rec, m_index, offsets, - page_is_leaf(m_page), + offsets = rec_get_offsets(rec, m_index, offsets, n_core, ULINT_UNDEFINED, &m_heap); total_recs_size += rec_offs_size(offsets); n_recs++; @@ -648,9 +650,11 @@ PageBulk::copyIn( ut_ad(m_rec_no == 0); ut_ad(page_rec_is_user_rec(rec)); + const ulint n_core = page_rec_is_leaf(rec) + ? m_index->n_core_fields : 0; + do { - offsets = rec_get_offsets(rec, m_index, offsets, - page_rec_is_leaf(split_rec), + offsets = rec_get_offsets(rec, m_index, offsets, n_core, ULINT_UNDEFINED, &m_heap); insert(rec, offsets); @@ -691,8 +695,10 @@ PageBulk::copyOut( /* Set last record's next in page */ rec_offs* offsets = NULL; rec = page_rec_get_prev(split_rec); - offsets = rec_get_offsets(rec, m_index, offsets, - page_rec_is_leaf(split_rec), + const ulint n_core = page_rec_is_leaf(split_rec) + ? m_index->n_core_fields : 0; + + offsets = rec_get_offsets(rec, m_index, offsets, n_core, ULINT_UNDEFINED, &m_heap); mach_write_to_2(rec - REC_NEXT, m_is_comp ? static_cast<uint16_t> @@ -703,8 +709,7 @@ PageBulk::copyOut( m_cur_rec = rec; m_heap_top = rec_get_end(rec, offsets); - offsets = rec_get_offsets(last_rec, m_index, offsets, - page_rec_is_leaf(split_rec), + offsets = rec_get_offsets(last_rec, m_index, offsets, n_core, ULINT_UNDEFINED, &m_heap); m_free_space += ulint(rec_get_end(last_rec, offsets) - m_heap_top) @@ -1118,7 +1123,8 @@ BtrBulk::insert( /* Convert tuple to rec. */ rec = rec_convert_dtuple_to_rec(static_cast<byte*>(mem_heap_alloc( page_bulk->m_heap, rec_size)), m_index, tuple, n_ext); - offsets = rec_get_offsets(rec, m_index, offsets, !level, + offsets = rec_get_offsets(rec, m_index, offsets, level + ? 0 : m_index->n_core_fields, ULINT_UNDEFINED, &page_bulk->m_heap); page_bulk->insert(rec, offsets); diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 18671308ece..7cf3301bdb9 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -592,7 +592,8 @@ incompatible: } mem_heap_t* heap = NULL; - rec_offs* offsets = rec_get_offsets(rec, index, NULL, true, + rec_offs* offsets = rec_get_offsets(rec, index, NULL, + index->n_core_fields, ULINT_UNDEFINED, &heap); if (rec_offs_any_default(offsets)) { inconsistent: @@ -2039,7 +2040,7 @@ retry_page_get: node_ptr = page_cur_get_rec(page_cursor); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); /* If the rec is the first or last in the page for @@ -2169,7 +2170,7 @@ need_opposite_intention: offsets2 = rec_get_offsets( first_rec, index, offsets2, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); cmp_rec_rec(node_ptr, first_rec, offsets, offsets2, index, false, &matched_fields); @@ -2187,7 +2188,7 @@ need_opposite_intention: offsets2 = rec_get_offsets( last_rec, index, offsets2, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); cmp_rec_rec( node_ptr, last_rec, offsets, offsets2, index, @@ -2356,7 +2357,7 @@ need_opposite_intention: offsets = rec_get_offsets( my_node_ptr, index, offsets, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); ulint my_page_no = btr_node_ptr_get_child_page_no( @@ -2781,7 +2782,7 @@ btr_cur_open_at_index_side_func( node_ptr = page_cur_get_rec(page_cursor); offsets = rec_get_offsets(node_ptr, cursor->index, offsets, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); /* If the rec is the first or last in the page for pessimistic delete intention, it might cause node_ptr insert @@ -3073,7 +3074,7 @@ btr_cur_open_at_rnd_pos_func( node_ptr = page_cur_get_rec(page_cursor); offsets = rec_get_offsets(node_ptr, cursor->index, offsets, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); /* If the rec is the first or last in the page for pessimistic delete intention, it might cause node_ptr insert @@ -4584,7 +4585,7 @@ btr_cur_optimistic_update( ut_ad(fil_page_index_page_check(page)); ut_ad(btr_page_get_index_id(page) == index->id); - *offsets = rec_get_offsets(rec, index, *offsets, true, + *offsets = rec_get_offsets(rec, index, *offsets, index->n_core_fields, ULINT_UNDEFINED, heap); #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG ut_a(!rec_offs_any_null_extern(rec, *offsets) @@ -5509,7 +5510,8 @@ btr_cur_optimistic_delete_func( rec = btr_cur_get_rec(cursor); - offsets = rec_get_offsets(rec, cursor->index, offsets, true, + offsets = rec_get_offsets(rec, cursor->index, offsets, + cursor->index->n_core_fields, ULINT_UNDEFINED, &heap); const ibool no_compress_needed = !rec_offs_any_extern(offsets) @@ -5717,7 +5719,8 @@ btr_cur_pessimistic_delete( ut_a(!page_zip || page_zip_validate(page_zip, page, index)); #endif /* UNIV_ZIP_DEBUG */ - offsets = rec_get_offsets(rec, index, NULL, page_is_leaf(page), + offsets = rec_get_offsets(rec, index, NULL, page_is_leaf(page) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); if (rec_offs_any_extern(offsets)) { @@ -5818,7 +5821,7 @@ discard_page: pointer as the predefined minimum record */ min_mark_next_rec = true; - } else if (dict_index_is_spatial(index)) { + } else if (index->is_spatial()) { /* For rtree, if delete the leftmost node pointer, we need to update parent page. */ rtr_mbr_t father_mbr; @@ -5833,7 +5836,7 @@ discard_page: &father_cursor); offsets = rec_get_offsets( btr_cur_get_rec(&father_cursor), index, NULL, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); father_rec = btr_cur_get_rec(&father_cursor); rtr_read_mbr(rec_get_nth_field( @@ -6753,12 +6756,13 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index) page = btr_cur_get_page(&cursor); rec = page_rec_get_next(page_get_infimum_rec(page)); - const bool is_leaf = page_is_leaf(page); + const ulint n_core = page_is_leaf(page) + ? index->n_core_fields : 0; if (!page_rec_is_supremum(rec)) { not_empty_flag = 1; offsets_rec = rec_get_offsets(rec, index, offsets_rec, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); if (n_not_null != NULL) { @@ -6779,7 +6783,7 @@ btr_estimate_number_of_different_key_vals(dict_index_t* index) offsets_next_rec = rec_get_offsets(next_rec, index, offsets_next_rec, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index 2c4c338ce70..ebe9854b5dc 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (C) 2012, 2014 Facebook, Inc. All Rights Reserved. -Copyright (C) 2014, 2020, MariaDB Corporation. +Copyright (C) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -384,12 +384,12 @@ btr_defragment_calc_n_recs_for_size( ulint size = 0; page_cur_t cur; + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; page_cur_set_before_first(block, &cur); page_cur_move_to_next(&cur); while (page_cur_get_rec(&cur) != page_get_supremum_rec(page)) { rec_t* cur_rec = page_cur_get_rec(&cur); - offsets = rec_get_offsets(cur_rec, index, offsets, - page_is_leaf(page), + offsets = rec_get_offsets(cur_rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); ulint rec_size = rec_offs_size(offsets); size += rec_size; @@ -401,6 +401,9 @@ btr_defragment_calc_n_recs_for_size( page_cur_move_to_next(&cur); } *n_recs_size = size; + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } return n_recs; } diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index 27ca51c3c3a..574998a9f3f 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -61,6 +61,7 @@ btr_pcur_reset( cursor->btr_cur.index = NULL; cursor->btr_cur.page_cur.rec = NULL; cursor->old_rec = NULL; + cursor->old_n_core_fields = 0; cursor->old_n_fields = 0; cursor->old_stored = false; @@ -184,19 +185,21 @@ before_first: if (index->is_ibuf()) { ut_ad(!index->table->not_redundant()); - cursor->old_n_fields = rec_get_n_fields_old(rec); - } else if (page_rec_is_leaf(rec)) { - cursor->old_n_fields = dict_index_get_n_unique_in_tree(index); - } else if (index->is_spatial()) { - ut_ad(dict_index_get_n_unique_in_tree_nonleaf(index) - == DICT_INDEX_SPATIAL_NODEPTR_SIZE); - /* For R-tree, we have to compare - the child page numbers as well. */ - cursor->old_n_fields = DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1; + cursor->old_n_fields = uint16_t(rec_get_n_fields_old(rec)); } else { - cursor->old_n_fields = dict_index_get_n_unique_in_tree(index); + cursor->old_n_fields = static_cast<uint16>( + dict_index_get_n_unique_in_tree(index)); + if (index->is_spatial() && !page_rec_is_leaf(rec)) { + ut_ad(dict_index_get_n_unique_in_tree_nonleaf(index) + == DICT_INDEX_SPATIAL_NODEPTR_SIZE); + /* For R-tree, we have to compare + the child page numbers as well. */ + cursor->old_n_fields + = DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1; + } } + cursor->old_n_core_fields = index->n_core_fields; cursor->old_rec = rec_copy_prefix_to_buf(rec, index, cursor->old_n_fields, &cursor->old_rec_buf, @@ -231,6 +234,7 @@ btr_pcur_copy_stored_position( + (pcur_donate->old_rec - pcur_donate->old_rec_buf); } + pcur_receive->old_n_core_fields = pcur_donate->old_n_core_fields; pcur_receive->old_n_fields = pcur_donate->old_n_fields; } @@ -322,6 +326,8 @@ btr_pcur_restore_position_func( } ut_a(cursor->old_rec); + ut_a(cursor->old_n_core_fields); + ut_a(cursor->old_n_core_fields <= index->n_core_fields); ut_a(cursor->old_n_fields); switch (latch_mode) { @@ -355,11 +361,16 @@ btr_pcur_restore_position_func( rec_offs_init(offsets2_); heap = mem_heap_create(256); + ut_ad(cursor->old_n_core_fields + == index->n_core_fields); + offsets1 = rec_get_offsets( - cursor->old_rec, index, offsets1, true, + cursor->old_rec, index, offsets1, + cursor->old_n_core_fields, cursor->old_n_fields, &heap); offsets2 = rec_get_offsets( - rec, index, offsets2, true, + rec, index, offsets2, + index->n_core_fields, cursor->old_n_fields, &heap); ut_ad(!cmp_rec_rec(cursor->old_rec, @@ -384,8 +395,14 @@ btr_pcur_restore_position_func( heap = mem_heap_create(256); - tuple = dict_index_build_data_tuple(cursor->old_rec, index, true, - cursor->old_n_fields, heap); + tuple = dtuple_create(heap, cursor->old_n_fields); + + dict_index_copy_types(tuple, index, cursor->old_n_fields); + + rec_copy_prefix_to_dtuple(tuple, cursor->old_rec, index, + cursor->old_n_core_fields, + cursor->old_n_fields, heap); + ut_ad(dtuple_check_typed(tuple)); /* Save the old search mode of the cursor */ old_mode = cursor->search_mode; @@ -424,7 +441,8 @@ btr_pcur_restore_position_func( && btr_pcur_is_on_user_rec(cursor) && !cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor), rec_get_offsets(btr_pcur_get_rec(cursor), - index, offsets, true, + index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap))) { /* We have to store the NEW value for the modify clock, diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc index b00009820a8..f22e3a5991b 100644 --- a/storage/innobase/btr/btr0sea.cc +++ b/storage/innobase/btr/btr0sea.cc @@ -737,7 +737,8 @@ btr_search_update_hash_ref( ulint fold = rec_fold( rec, - rec_get_offsets(rec, index, offsets_, true, + rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap), block->curr_n_fields, block->curr_n_bytes, index->id); @@ -795,7 +796,8 @@ btr_search_check_guess( match = 0; - offsets = rec_get_offsets(rec, cursor->index, offsets, true, + offsets = rec_get_offsets(rec, cursor->index, offsets, + cursor->index->n_core_fields, n_unique, &heap); cmp = cmp_dtuple_rec_with_match(tuple, rec, offsets, &match); @@ -846,7 +848,8 @@ btr_search_check_guess( } offsets = rec_get_offsets(prev_rec, cursor->index, offsets, - true, n_unique, &heap); + cursor->index->n_core_fields, + n_unique, &heap); cmp = cmp_dtuple_rec_with_match( tuple, prev_rec, offsets, &match); if (mode == PAGE_CUR_GE) { @@ -869,7 +872,8 @@ btr_search_check_guess( } offsets = rec_get_offsets(next_rec, cursor->index, offsets, - true, n_unique, &heap); + cursor->index->n_core_fields, + n_unique, &heap); cmp = cmp_dtuple_rec_with_match( tuple, next_rec, offsets, &match); if (mode == PAGE_CUR_LE) { @@ -1344,7 +1348,7 @@ retry: while (!page_rec_is_supremum(rec)) { offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id); @@ -1568,7 +1572,7 @@ btr_search_build_page_hash_index( ut_a(index->id == btr_page_get_index_id(page)); offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); ut_ad(page_rec_is_supremum(rec) @@ -1599,7 +1603,7 @@ btr_search_build_page_hash_index( } offsets = rec_get_offsets( - next_rec, index, offsets, true, + next_rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, n_bytes, index->id); @@ -1840,7 +1844,8 @@ void btr_search_update_hash_on_delete(btr_cur_t* cursor) rec = btr_cur_get_rec(cursor); - fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_, true, + fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap), block->curr_n_fields, block->curr_n_bytes, index->id); if (UNIV_LIKELY_NULL(heap)) { @@ -2013,13 +2018,14 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch) ins_rec = page_rec_get_next_const(rec); next_rec = page_rec_get_next_const(ins_rec); - offsets = rec_get_offsets(ins_rec, index, offsets, true, + offsets = rec_get_offsets(ins_rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id); if (!page_rec_is_supremum(next_rec)) { offsets = rec_get_offsets( - next_rec, index, offsets, true, + next_rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); next_fold = rec_fold(next_rec, offsets, n_fields, n_bytes, index->id); @@ -2031,7 +2037,7 @@ btr_search_update_hash_on_insert(btr_cur_t* cursor, rw_lock_t* ahi_latch) if (!page_rec_is_infimum(rec) && !rec_is_metadata(rec, *index)) { offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, index->n_core_fields, btr_search_get_n_fields(n_fields, n_bytes), &heap); fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id); } else { @@ -2259,7 +2265,8 @@ state_ok: page_index_id = btr_page_get_index_id(block->frame); offsets = rec_get_offsets( - node->data, block->index, offsets, true, + node->data, block->index, offsets, + block->index->n_core_fields, btr_search_get_n_fields(block->curr_n_fields, block->curr_n_bytes), &heap); diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index f613162fb04..06a38f49212 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -2,7 +2,7 @@ Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -255,7 +255,7 @@ dict_table_try_drop_aborted( && !UT_LIST_GET_FIRST(table->locks)) { /* Silence a debug assertion in row_merge_drop_indexes(). */ ut_d(table->acquire()); - row_merge_drop_indexes(trx, table, TRUE); + row_merge_drop_indexes(trx, table, true); ut_d(table->release()); ut_ad(table->get_ref_count() == ref_count); trx_commit_for_mysql(trx); @@ -3866,7 +3866,9 @@ dict_index_build_node_ptr( dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4); - rec_copy_prefix_to_dtuple(tuple, rec, index, !level, n_unique, heap); + rec_copy_prefix_to_dtuple(tuple, rec, index, + level ? 0 : index->n_core_fields, + n_unique, heap); dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple) | REC_STATUS_NODE_PTR); @@ -3890,11 +3892,14 @@ dict_index_build_data_tuple( ulint n_fields, mem_heap_t* heap) { + ut_ad(!index->is_clust()); + dtuple_t* tuple = dtuple_create(heap, n_fields); dict_index_copy_types(tuple, index, n_fields); - rec_copy_prefix_to_dtuple(tuple, rec, index, leaf, n_fields, heap); + rec_copy_prefix_to_dtuple(tuple, rec, index, + leaf ? n_fields : 0, n_fields, heap); ut_ad(dtuple_check_typed(tuple)); diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index 96f2d7b6e3b..97889e22981 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -2,7 +2,7 @@ Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -938,7 +938,7 @@ dict_mem_fill_vcol_from_v_indexes( Later virtual column set will be refreshed during loading of table. */ if (!dict_index_has_virtual(index) - || index->has_new_v_col) { + || index->has_new_v_col()) { continue; } @@ -1377,7 +1377,8 @@ dict_index_t::vers_history_row( rec_t* clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, this, &clust_index, &mtr); if (clust_rec) { - offsets = rec_get_offsets(clust_rec, clust_index, offsets, true, + offsets = rec_get_offsets(clust_rec, clust_index, offsets, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); history_row = clust_index->vers_history_row(clust_rec, offsets); diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 8386cc80d81..42f75252cee 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1156,7 +1156,7 @@ dict_stats_analyze_index_level( prev_rec_offsets = rec_get_offsets( prev_rec, index, prev_rec_offsets, - true, + index->n_core_fields, n_uniq, &heap); prev_rec = rec_copy_prefix_to_buf( @@ -1168,8 +1168,9 @@ dict_stats_analyze_index_level( continue; } - rec_offsets = rec_get_offsets( - rec, index, rec_offsets, !level, n_uniq, &heap); + rec_offsets = rec_get_offsets(rec, index, rec_offsets, + level ? 0 : index->n_core_fields, + n_uniq, &heap); (*total_recs)++; @@ -1177,7 +1178,8 @@ dict_stats_analyze_index_level( ulint matched_fields; prev_rec_offsets = rec_get_offsets( - prev_rec, index, prev_rec_offsets, !level, + prev_rec, index, prev_rec_offsets, + level ? 0 : index->n_core_fields, n_uniq, &heap); cmp_rec_rec(prev_rec, rec, @@ -1331,7 +1333,7 @@ be big enough) @param[in] index index of the page @param[in] page the page to scan @param[in] n_prefix look at the first n_prefix columns -@param[in] is_leaf whether this is the leaf page +@param[in] n_core 0, or index->n_core_fields for leaf @param[out] n_diff number of distinct records encountered @param[out] n_external_pages if this is non-NULL then it will be set to the number of externally stored pages which were encountered @@ -1346,7 +1348,7 @@ dict_stats_scan_page( const dict_index_t* index, const page_t* page, ulint n_prefix, - bool is_leaf, + ulint n_core, ib_uint64_t* n_diff, ib_uint64_t* n_external_pages) { @@ -1358,9 +1360,9 @@ dict_stats_scan_page( Because offsets1,offsets2 should be big enough, this memory heap should never be used. */ mem_heap_t* heap = NULL; - ut_ad(is_leaf == page_is_leaf(page)); + ut_ad(!!n_core == page_is_leaf(page)); const rec_t* (*get_next)(const rec_t*) - = !is_leaf || srv_stats_include_delete_marked + = !n_core || srv_stats_include_delete_marked ? page_rec_get_next_const : page_rec_get_next_non_del_marked; @@ -1379,7 +1381,7 @@ dict_stats_scan_page( return(NULL); } - offsets_rec = rec_get_offsets(rec, index, offsets_rec, is_leaf, + offsets_rec = rec_get_offsets(rec, index, offsets_rec, n_core, ULINT_UNDEFINED, &heap); if (should_count_external_pages) { @@ -1396,7 +1398,7 @@ dict_stats_scan_page( ulint matched_fields; offsets_next_rec = rec_get_offsets(next_rec, index, - offsets_next_rec, is_leaf, + offsets_next_rec, n_core, ULINT_UNDEFINED, &heap); @@ -1410,7 +1412,7 @@ dict_stats_scan_page( (*n_diff)++; - if (!is_leaf) { + if (!n_core) { break; } } @@ -1497,7 +1499,7 @@ dict_stats_analyze_index_below_cur( page = page_align(rec); ut_ad(!page_rec_is_leaf(rec)); - offsets_rec = rec_get_offsets(rec, index, offsets1, false, + offsets_rec = rec_get_offsets(rec, index, offsets1, 0, ULINT_UNDEFINED, &heap); page_id_t page_id(index->table->space_id, @@ -1533,7 +1535,7 @@ dict_stats_analyze_index_below_cur( /* search for the first non-boring record on the page */ offsets_rec = dict_stats_scan_page( &rec, offsets1, offsets2, index, page, n_prefix, - false, n_diff, NULL); + 0, n_diff, NULL); /* pages on level > 0 are not allowed to be empty */ ut_a(offsets_rec != NULL); @@ -1578,7 +1580,7 @@ dict_stats_analyze_index_below_cur( offsets_rec = dict_stats_scan_page( &rec, offsets1, offsets2, index, page, n_prefix, - true, n_diff, + index->n_core_fields, n_diff, n_external_pages); #if 0 diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc index bd7ae83b53a..afeb8ef6c77 100644 --- a/storage/innobase/dict/dict0stats_bg.cc +++ b/storage/innobase/dict/dict0stats_bg.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2012, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -146,9 +146,24 @@ schedule new estimates for table and index statistics to be calculated. void dict_stats_update_if_needed_func(dict_table_t *table) #endif { - ut_ad(table->stat_initialized); ut_ad(!mutex_own(&dict_sys.mutex)); + if (UNIV_UNLIKELY(!table->stat_initialized)) { + /* The table may have been evicted from dict_sys + and reloaded internally by InnoDB for FOREIGN KEY + processing, but not reloaded by the SQL layer. + + We can (re)compute the transient statistics when the + table is actually loaded by the SQL layer. + + Note: If InnoDB persistent statistics are enabled, + we will skip the updates. We must do this, because + dict_table_get_n_rows() below assumes that the + statistics have been initialized. The DBA may have + to execute ANALYZE TABLE. */ + return; + } + ulonglong counter = table->stat_modified_counter++; ulonglong n_rows = dict_table_get_n_rows(table); diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index d35da0fe843..cc0a41042af 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2505,7 +2505,8 @@ fts_get_max_cache_size( } } else { ib::error() << "(" << error << ") reading max" - " cache config value from config table"; + " cache config value from config table " + << fts_table->table->name; } ut_free(value.f_str); @@ -2678,7 +2679,8 @@ func_exit: } else { *doc_id = 0; - ib::error() << "(" << error << ") while getting next doc id."; + ib::error() << "(" << error << ") while getting next doc id " + "for table " << table->name; fts_sql_rollback(trx); if (error == DB_DEADLOCK) { @@ -2758,7 +2760,8 @@ fts_update_sync_doc_id( cache->synced_doc_id = doc_id; } else { ib::error() << "(" << error << ") while" - " updating last doc id."; + " updating last doc id for table" + << table->name; fts_sql_rollback(trx); } @@ -3469,7 +3472,8 @@ fts_add_doc_by_id( } - offsets = rec_get_offsets(clust_rec, clust_index, NULL, true, + offsets = rec_get_offsets(clust_rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); for (ulint i = 0; i < num_idx; ++i) { @@ -3983,7 +3987,8 @@ fts_sync_write_words( if (UNIV_UNLIKELY(error != DB_SUCCESS) && !print_error) { ib::error() << "(" << error << ") writing" - " word node to FTS auxiliary index table."; + " word node to FTS auxiliary index table " + << table->name; print_error = TRUE; } } @@ -4138,7 +4143,8 @@ fts_sync_commit( fts_sql_commit(trx); } else { fts_sql_rollback(trx); - ib::error() << "(" << error << ") during SYNC."; + ib::error() << "(" << error << ") during SYNC of " + "table " << sync->table->name; } if (UNIV_UNLIKELY(fts_enable_diag_print) && elapsed_time) { @@ -4901,7 +4907,8 @@ fts_get_rows_count( trx->error_state = DB_SUCCESS; } else { ib::error() << "(" << error - << ") while reading FTS table."; + << ") while reading FTS table " + << table_name; break; /* Exit the loop. */ } diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index 2e50d1b2cad..22e6e08f139 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2020, MariaDB Corporation. +Copyright (c) 2018, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -87,8 +87,9 @@ rtr_page_split_initialize_nodes( stop = task + n_recs; rec = page_rec_get_next(page_get_infimum_rec(page)); - const bool is_leaf = page_is_leaf(page); - *offsets = rec_get_offsets(rec, cursor->index, *offsets, is_leaf, + const ulint n_core = page_is_leaf(page) + ? cursor->index->n_core_fields : 0; + *offsets = rec_get_offsets(rec, cursor->index, *offsets, n_core, n_uniq, &heap); source_cur = rec_get_nth_field(rec, *offsets, 0, &len); @@ -101,7 +102,7 @@ rtr_page_split_initialize_nodes( rec = page_rec_get_next(rec); *offsets = rec_get_offsets(rec, cursor->index, *offsets, - is_leaf, n_uniq, &heap); + n_core, n_uniq, &heap); source_cur = rec_get_nth_field(rec, *offsets, 0, &len); } @@ -230,7 +231,8 @@ rtr_update_mbr_field( ut_ad(page == buf_block_get_frame(block)); child = btr_node_ptr_get_child_page_no(rec, offsets); - const bool is_leaf = page_is_leaf(block->frame); + const ulint n_core = page_is_leaf(block->frame) + ? index->n_core_fields : 0; if (new_rec) { child_rec = new_rec; @@ -246,7 +248,7 @@ rtr_update_mbr_field( if (cursor2) { rec_t* del_rec = btr_cur_get_rec(cursor2); offsets2 = rec_get_offsets(btr_cur_get_rec(cursor2), - index, NULL, false, + index, NULL, 0, ULINT_UNDEFINED, &heap); del_page_no = btr_node_ptr_get_child_page_no(del_rec, offsets2); cur2_pos = page_rec_get_n_recs_before(btr_cur_get_rec(cursor2)); @@ -313,7 +315,7 @@ rtr_update_mbr_field( = page_rec_get_nth(page, cur2_pos); } offsets2 = rec_get_offsets(btr_cur_get_rec(cursor2), - index, NULL, false, + index, NULL, 0, ULINT_UNDEFINED, &heap); ut_ad(del_page_no == btr_node_ptr_get_child_page_no( cursor2->page_cur.rec, @@ -351,7 +353,7 @@ rtr_update_mbr_field( ut_ad(old_rec != insert_rec); page_cur_position(old_rec, block, &page_cur); - offsets2 = rec_get_offsets(old_rec, index, NULL, is_leaf, + offsets2 = rec_get_offsets(old_rec, index, NULL, n_core, ULINT_UNDEFINED, &heap); page_cur_delete_rec(&page_cur, index, offsets2, mtr); @@ -381,7 +383,7 @@ update_mbr: cur2_rec = cursor2->page_cur.rec; offsets2 = rec_get_offsets(cur2_rec, index, NULL, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); cur2_rec_info = rec_get_info_bits(cur2_rec, @@ -441,7 +443,7 @@ update_mbr: if (ins_suc) { btr_cur_position(index, insert_rec, block, cursor); offsets = rec_get_offsets(insert_rec, - index, offsets, is_leaf, + index, offsets, n_core, ULINT_UNDEFINED, &heap); } @@ -456,7 +458,7 @@ update_mbr: cur2_rec = btr_cur_get_rec(cursor2); offsets2 = rec_get_offsets(cur2_rec, index, NULL, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); /* If the cursor2 position is on a wrong rec, we @@ -470,7 +472,7 @@ update_mbr: while (!page_rec_is_supremum(cur2_rec)) { offsets2 = rec_get_offsets(cur2_rec, index, NULL, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); cur2_pno = btr_node_ptr_get_child_page_no( @@ -747,7 +749,8 @@ rtr_split_page_move_rec_list( rec_move = static_cast<rtr_rec_move_t*>(mem_heap_alloc( heap, sizeof (*rec_move) * max_to_move)); - const bool is_leaf = page_is_leaf(page); + const ulint n_core = page_is_leaf(page) + ? index->n_core_fields : 0; /* Insert the recs in group 2 to new page. */ for (cur_split_node = node_array; @@ -757,10 +760,10 @@ rtr_split_page_move_rec_list( block, cur_split_node->key); offsets = rec_get_offsets(cur_split_node->key, - index, offsets, is_leaf, + index, offsets, n_core, ULINT_UNDEFINED, &heap); - ut_ad(!is_leaf || cur_split_node->key != first_rec); + ut_ad(!n_core || cur_split_node->key != first_rec); rec = page_cur_insert_rec_low( &new_page_cursor, @@ -792,7 +795,7 @@ rtr_split_page_move_rec_list( same temp-table in parallel. max_trx_id is ignored for temp tables because it not required for MVCC. */ - if (is_leaf && !index->table->is_temporary()) { + if (n_core && !index->table->is_temporary()) { page_update_max_trx_id(new_block, NULL, page_get_max_trx_id(page), mtr); @@ -846,7 +849,7 @@ rtr_split_page_move_rec_list( block, &page_cursor); offsets = rec_get_offsets( page_cur_get_rec(&page_cursor), index, - offsets, is_leaf, ULINT_UNDEFINED, + offsets, n_core, ULINT_UNDEFINED, &heap); page_cur_delete_rec(&page_cursor, index, offsets, mtr); @@ -1050,6 +1053,9 @@ func_start: /* Update the lock table */ lock_rtr_move_rec_list(new_block, block, rec_move, moved); + const ulint n_core = page_level + ? 0 : cursor->index->n_core_fields; + /* Delete recs in first group from the new page. */ for (cur_split_node = rtr_split_node_array; cur_split_node < end_split_node - 1; ++cur_split_node) { @@ -1068,7 +1074,7 @@ func_start: *offsets = rec_get_offsets( page_cur_get_rec(page_cursor), - cursor->index, *offsets, !page_level, + cursor->index, *offsets, n_core, ULINT_UNDEFINED, heap); page_cur_delete_rec(page_cursor, @@ -1085,7 +1091,7 @@ func_start: block, page_cursor); *offsets = rec_get_offsets( page_cur_get_rec(page_cursor), - cursor->index, *offsets, !page_level, + cursor->index, *offsets, n_core, ULINT_UNDEFINED, heap); page_cur_delete_rec(page_cursor, cursor->index, *offsets, mtr); @@ -1313,7 +1319,8 @@ rtr_page_copy_rec_list_end_no_locks( rec_offs offsets_2[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets2 = offsets_2; ulint moved = 0; - bool is_leaf = page_is_leaf(new_page); + const ulint n_core = page_is_leaf(new_page) + ? index->n_core_fields : 0; rec_offs_init(offsets_1); rec_offs_init(offsets_2); @@ -1342,14 +1349,14 @@ rtr_page_copy_rec_list_end_no_locks( cur_rec = page_rec_get_next(cur_rec); } - offsets1 = rec_get_offsets(cur1_rec, index, offsets1, is_leaf, + offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); while (!page_rec_is_supremum(cur_rec)) { ulint cur_matched_fields = 0; int cmp; offsets2 = rec_get_offsets(cur_rec, index, offsets2, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); cmp = cmp_rec_rec(cur1_rec, cur_rec, offsets1, offsets2, index, false, @@ -1361,7 +1368,7 @@ rtr_page_copy_rec_list_end_no_locks( /* Skip small recs. */ page_cur_move_to_next(&page_cur); cur_rec = page_cur_get_rec(&page_cur); - } else if (is_leaf) { + } else if (n_core) { if (rec_get_deleted_flag(cur1_rec, dict_table_is_comp(index->table))) { goto next; @@ -1384,7 +1391,7 @@ rtr_page_copy_rec_list_end_no_locks( cur_rec = page_cur_get_rec(&page_cur); - offsets1 = rec_get_offsets(cur1_rec, index, offsets1, is_leaf, + offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); ins_rec = page_cur_insert_rec_low(&page_cur, index, @@ -1440,7 +1447,8 @@ rtr_page_copy_rec_list_start_no_locks( rec_offs* offsets2 = offsets_2; page_cur_t page_cur; ulint moved = 0; - bool is_leaf = page_is_leaf(buf_block_get_frame(block)); + const ulint n_core = page_is_leaf(buf_block_get_frame(block)) + ? index->n_core_fields : 0; rec_offs_init(offsets_1); rec_offs_init(offsets_2); @@ -1460,14 +1468,14 @@ rtr_page_copy_rec_list_start_no_locks( cur_rec = page_rec_get_next(cur_rec); } - offsets1 = rec_get_offsets(cur1_rec, index, offsets1, is_leaf, + offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); while (!page_rec_is_supremum(cur_rec)) { ulint cur_matched_fields = 0; offsets2 = rec_get_offsets(cur_rec, index, offsets2, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); int cmp = cmp_rec_rec(cur1_rec, cur_rec, offsets1, offsets2, index, false, @@ -1480,7 +1488,7 @@ rtr_page_copy_rec_list_start_no_locks( /* Skip small recs. */ page_cur_move_to_next(&page_cur); cur_rec = page_cur_get_rec(&page_cur); - } else if (is_leaf) { + } else if (n_core) { if (rec_get_deleted_flag( cur1_rec, dict_table_is_comp(index->table))) { @@ -1504,7 +1512,7 @@ rtr_page_copy_rec_list_start_no_locks( cur_rec = page_cur_get_rec(&page_cur); - offsets1 = rec_get_offsets(cur1_rec, index, offsets1, is_leaf, + offsets1 = rec_get_offsets(cur1_rec, index, offsets1, n_core, ULINT_UNDEFINED, &heap); ins_rec = page_cur_insert_rec_low(&page_cur, index, @@ -1655,7 +1663,7 @@ rtr_check_same_block( while (!page_rec_is_supremum(rec)) { offsets = rec_get_offsets( - rec, index, NULL, false, ULINT_UNDEFINED, &heap); + rec, index, NULL, 0, ULINT_UNDEFINED, &heap); if (btr_node_ptr_get_child_page_no(rec, offsets) == page_no) { btr_cur_position(index, rec, parentb, cursor); diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index d9a0ae80c33..1c22aab4d00 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2016, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -529,8 +529,7 @@ rtr_compare_cursor_rec( rec = btr_cur_get_rec(cursor); - offsets = rec_get_offsets( - rec, index, NULL, false, ULINT_UNDEFINED, heap); + offsets = rec_get_offsets(rec, index, NULL, 0, ULINT_UNDEFINED, heap); return(btr_node_ptr_get_child_page_no(rec, offsets) == page_no); } @@ -831,7 +830,8 @@ rtr_page_get_father_node_ptr( user_rec = btr_cur_get_rec(cursor); ut_a(page_rec_is_user_rec(user_rec)); - offsets = rec_get_offsets(user_rec, index, offsets, !level, + offsets = rec_get_offsets(user_rec, index, offsets, + level ? 0 : index->n_fields, ULINT_UNDEFINED, &heap); rtr_get_mbr_from_rec(user_rec, offsets, &mbr); @@ -848,7 +848,7 @@ rtr_page_get_father_node_ptr( node_ptr = btr_cur_get_rec(cursor); ut_ad(!page_rec_is_comp(node_ptr) || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); ulint child_page = btr_node_ptr_get_child_page_no(node_ptr, offsets); @@ -866,13 +866,14 @@ rtr_page_get_father_node_ptr( print_rec = page_rec_get_next( page_get_infimum_rec(page_align(user_rec))); offsets = rec_get_offsets(print_rec, index, offsets, - page_rec_is_leaf(user_rec), + page_rec_is_leaf(user_rec) + ? index->n_fields : 0, ULINT_UNDEFINED, &heap); error << "; child "; rec_print(error.m_oss, print_rec, rec_get_info_bits(print_rec, rec_offs_comp(offsets)), offsets); - offsets = rec_get_offsets(node_ptr, index, offsets, false, + offsets = rec_get_offsets(node_ptr, index, offsets, 0, ULINT_UNDEFINED, &heap); error << "; parent "; rec_print(error.m_oss, print_rec, @@ -1304,10 +1305,12 @@ rtr_cur_restore_position( heap = mem_heap_create(256); offsets1 = rec_get_offsets( - r_cursor->old_rec, index, NULL, !level, + r_cursor->old_rec, index, NULL, + level ? 0 : r_cursor->old_n_fields, r_cursor->old_n_fields, &heap); offsets2 = rec_get_offsets( - rec, index, NULL, !level, + rec, index, NULL, + level ? 0 : r_cursor->old_n_fields, r_cursor->old_n_fields, &heap); comp = rec_offs_comp(offsets1); @@ -1374,12 +1377,12 @@ search_again: rec = btr_pcur_get_rec(r_cursor); - offsets1 = rec_get_offsets( - r_cursor->old_rec, index, NULL, !level, - r_cursor->old_n_fields, &heap); - offsets2 = rec_get_offsets( - rec, index, NULL, !level, - r_cursor->old_n_fields, &heap); + offsets1 = rec_get_offsets(r_cursor->old_rec, index, NULL, + level ? 0 : r_cursor->old_n_fields, + r_cursor->old_n_fields, &heap); + offsets2 = rec_get_offsets(rec, index, NULL, + level ? 0 : r_cursor->old_n_fields, + r_cursor->old_n_fields, &heap); comp = rec_offs_comp(offsets1); @@ -1716,7 +1719,7 @@ rtr_cur_search_with_match( page = buf_block_get_frame(block); const ulint level = btr_page_get_level(page); - const bool is_leaf = !level; + const ulint n_core = level ? 0 : index->n_fields; if (mode == PAGE_CUR_RTREE_LOCATE) { ut_ad(level != 0); @@ -1738,7 +1741,7 @@ rtr_cur_search_with_match( ulint new_rec_size = rec_get_converted_size(index, tuple, 0); - offsets = rec_get_offsets(rec, index, offsets, is_leaf, + offsets = rec_get_offsets(rec, index, offsets, n_core, dtuple_get_n_fields_cmp(tuple), &heap); @@ -1759,7 +1762,7 @@ rtr_cur_search_with_match( } while (!page_rec_is_supremum(rec)) { - if (!is_leaf) { + if (!n_core) { switch (mode) { case PAGE_CUR_CONTAIN: case PAGE_CUR_INTERSECT: @@ -1840,7 +1843,7 @@ rtr_cur_search_with_match( to rtr_info->path for non-leaf nodes, or rtr_info->matches for leaf nodes */ if (rtr_info && mode != PAGE_CUR_RTREE_INSERT) { - if (!is_leaf) { + if (!n_core) { uint32_t page_no; node_seq_t new_seq; bool is_loc; @@ -1851,7 +1854,7 @@ rtr_cur_search_with_match( == PAGE_CUR_RTREE_GET_FATHER); offsets = rec_get_offsets( - rec, index, offsets, false, + rec, index, offsets, 0, ULINT_UNDEFINED, &heap); page_no = btr_node_ptr_get_child_page_no( @@ -1904,7 +1907,8 @@ rtr_cur_search_with_match( /* Collect matched records on page */ offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, + index->n_fields, ULINT_UNDEFINED, &heap); rtr_leaf_push_match_rec( rec, rtr_info, offsets, @@ -1927,7 +1931,7 @@ rtr_cur_search_with_match( /* All records on page are searched */ if (page_rec_is_supremum(rec)) { - if (!is_leaf) { + if (!n_core) { if (!found) { /* No match case, if it is for insertion, then we select the record that result in @@ -1936,7 +1940,7 @@ rtr_cur_search_with_match( ut_ad(least_inc < DBL_MAX); offsets = rec_get_offsets( best_rec, index, offsets, - false, ULINT_UNDEFINED, &heap); + 0, ULINT_UNDEFINED, &heap); uint32_t child_no = btr_node_ptr_get_child_page_no( best_rec, offsets); @@ -1988,11 +1992,11 @@ rtr_cur_search_with_match( /* Verify the record to be positioned is the same as the last record in matched_rec vector */ offsets2 = rec_get_offsets(test_rec.r_rec, index, - offsets2, true, + offsets2, index->n_fields, ULINT_UNDEFINED, &heap); offsets = rec_get_offsets(last_match_rec, index, - offsets, true, + offsets, index->n_fields, ULINT_UNDEFINED, &heap); ut_ad(cmp_rec_rec(test_rec.r_rec, last_match_rec, @@ -2012,7 +2016,7 @@ rtr_cur_search_with_match( mach_read_from_4(rec + DATA_MBR_LEN), block, rec, 0); - } else if (rtr_info && found && !is_leaf) { + } else if (rtr_info && found && !n_core) { rec = last_match_rec; } @@ -2022,11 +2026,11 @@ rtr_cur_search_with_match( #ifdef UNIV_DEBUG /* Verify that we are positioned at the same child page as pushed in the path stack */ - if (!is_leaf && (!page_rec_is_supremum(rec) || found) + if (!n_core && (!page_rec_is_supremum(rec) || found) && mode != PAGE_CUR_RTREE_INSERT) { ulint page_no; - offsets = rec_get_offsets(rec, index, offsets, false, + offsets = rec_get_offsets(rec, index, offsets, 0, ULINT_UNDEFINED, &heap); page_no = btr_node_ptr_get_child_page_no(rec, offsets); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7c74d4f8340..454d74d1015 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8277,26 +8277,24 @@ wsrep_calc_row_hash( dictionary */ row_prebuilt_t* prebuilt) /*!< in: InnoDB prebuilt struct */ { - ulint len; - const byte* ptr; - void *ctx = alloca(my_md5_context_size()); my_md5_init(ctx); for (uint i = 0; i < table->s->fields; i++) { byte null_byte=0; byte true_byte=1; + unsigned is_unsigned; const Field* field = table->field[i]; if (!field->stored_in_db()) { continue; } - ptr = (const byte*) row + get_field_offset(table, field); - len = field->pack_length(); - - switch (prebuilt->table->cols[i].mtype) { + auto ptr = row + get_field_offset(table, field); + ulint len = field->pack_length(); + switch (get_innobase_type_from_mysql_type(&is_unsigned, + field)) { case DATA_BLOB: ptr = row_mysql_read_blob_ref(&len, ptr, len); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 44e45e19550..dfea7fcde8c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1022,13 +1022,6 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx @return whether the table will be rebuilt */ bool need_rebuild () const { return(old_table != new_table); } - /** Clear uncommmitted added indexes after a failed operation. */ - void clear_added_indexes() - { - for (ulint i= 0; i < num_to_add_index; i++) - add_index[i]->detach_columns(true); - } - /** Convert table-rebuilding ALTER to instant ALTER. */ void prepare_instant() { @@ -1126,6 +1119,42 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx } } + /** @return whether the given column is being added */ + bool is_new_vcol(const dict_v_col_t &v_col) const + { + for (ulint i= 0; i < num_to_add_vcol; i++) + if (&add_vcol[i] == &v_col) + return true; + return false; + } + + /** During rollback, make newly added indexes point to + newly added virtual columns. */ + void clean_new_vcol_index() + { + ut_ad(old_table == new_table); + const dict_index_t *index= dict_table_get_first_index(old_table); + while ((index= dict_table_get_next_index(index)) != NULL) + { + if (!index->has_virtual() || index->is_committed()) + continue; + ulint n_drop_new_vcol= index->get_new_n_vcol(); + for (ulint i= 0; n_drop_new_vcol && i < index->n_fields; i++) + { + dict_col_t *col= index->fields[i].col; + /* Skip the non-virtual and old virtual columns */ + if (!col->is_virtual()) + continue; + dict_v_col_t *vcol= reinterpret_cast<dict_v_col_t*>(col); + if (!is_new_vcol(*vcol)) + continue; + + index->fields[i].col= &index->new_vcol_info-> + add_drop_v_col(index->heap, vcol, --n_drop_new_vcol)->m_col; + } + } + } + private: // Disable copying ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx&); @@ -3725,9 +3754,11 @@ innobase_fts_check_doc_id_index( for (index = dict_table_get_first_index(table); index; index = dict_table_get_next_index(index)) { + /* Check if there exists a unique index with the name of - FTS_DOC_ID_INDEX_NAME */ - if (innobase_strcasecmp(index->name, FTS_DOC_ID_INDEX_NAME)) { + FTS_DOC_ID_INDEX_NAME and ignore the corrupted index */ + if (index->type & DICT_CORRUPT + || innobase_strcasecmp(index->name, FTS_DOC_ID_INDEX_NAME)) { continue; } @@ -4035,7 +4066,7 @@ online_retry_drop_indexes_low( ut_ad(table->get_ref_count() >= 1); if (table->drop_aborted) { - row_merge_drop_indexes(trx, table, TRUE); + row_merge_drop_indexes(trx, table, true); } } @@ -5895,7 +5926,7 @@ add_all_virtual: offsets = rec_get_offsets( btr_pcur_get_rec(&pcur), index, offsets, - true, ULINT_UNDEFINED, &offsets_heap); + index->n_core_fields, ULINT_UNDEFINED, &offsets_heap); if (big_rec) { if (err == DB_SUCCESS) { err = btr_store_big_rec_extern_fields( @@ -6806,7 +6837,7 @@ new_table_failed: for (ulint a = 0; a < ctx->num_to_add_index; a++) { dict_index_t* index = ctx->add_index[a]; - const bool has_new_v_col = index->has_new_v_col; + const ulint n_v_col = index->get_new_n_vcol(); index = create_index_dict(ctx->trx, index, add_v); error = ctx->trx->error_state; if (error != DB_SUCCESS) { @@ -6836,7 +6867,9 @@ error_handling_drop_uncached_1: goto error_handling_drop_uncached_1; } index->parser = index_defs[a].parser; - index->has_new_v_col = has_new_v_col; + if (n_v_col) { + index->assign_new_v_col(n_v_col); + } /* Note the id of the transaction that created this index, we use it to restrict readers from accessing this index, to ensure read consistency. */ @@ -6907,7 +6940,7 @@ error_handling_drop_uncached_1: for (ulint a = 0; a < ctx->num_to_add_index; a++) { dict_index_t* index = ctx->add_index[a]; - const bool has_new_v_col = index->has_new_v_col; + const ulint n_v_col = index->get_new_n_vcol(); DBUG_EXECUTE_IF( "create_index_metadata_fail", if (a + 1 == ctx->num_to_add_index) { @@ -6939,7 +6972,9 @@ error_handling_drop_uncached: } index->parser = index_defs[a].parser; - index->has_new_v_col = has_new_v_col; + if (n_v_col) { + index->assign_new_v_col(n_v_col); + } /* Note the id of the transaction that created this index, we use it to restrict readers from accessing this index, to ensure read consistency. */ @@ -7168,7 +7203,7 @@ error_handled: online_retry_drop_indexes_with_trx(user_table, ctx->trx); } else { ut_ad(!ctx->need_rebuild()); - row_merge_drop_indexes(ctx->trx, user_table, TRUE); + row_merge_drop_indexes(ctx->trx, user_table, true); trx_commit_for_mysql(ctx->trx); } @@ -8531,7 +8566,6 @@ oom: that we hold at most a shared lock on the table. */ m_prebuilt->trx->error_info = NULL; ctx->trx->error_state = DB_SUCCESS; - ctx->clear_added_indexes(); DBUG_RETURN(true); } @@ -8623,17 +8657,18 @@ temparary index prefix @param table the TABLE @param locked TRUE=table locked, FALSE=may need to do a lazy drop @param trx the transaction -*/ -static MY_ATTRIBUTE((nonnull)) +@param alter_trx transaction which takes S-lock on the table + while creating the index */ +static void innobase_rollback_sec_index( -/*========================*/ - dict_table_t* user_table, - const TABLE* table, - ibool locked, - trx_t* trx) + dict_table_t* user_table, + const TABLE* table, + bool locked, + trx_t* trx, + const trx_t* alter_trx=NULL) { - row_merge_drop_indexes(trx, user_table, locked); + row_merge_drop_indexes(trx, user_table, locked, alter_trx); /* Free the table->fts only if there is no FTS_DOC_ID in the table */ @@ -8761,7 +8796,12 @@ rollback_inplace_alter_table( } innobase_rollback_sec_index( - prebuilt->table, table, FALSE, ctx->trx); + prebuilt->table, table, + (ha_alter_info->alter_info->requested_lock + == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE), + ctx->trx, prebuilt->trx); + + ctx->clean_new_vcol_index(); } trx_commit_for_mysql(ctx->trx); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 31ed11cd7eb..a3d6ed26cda 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -3775,7 +3775,7 @@ dump: row_ins_sec_index_entry_by_modify(BTR_MODIFY_LEAF). */ ut_ad(rec_get_deleted_flag(rec, page_is_comp(page))); - offsets = rec_get_offsets(rec, index, NULL, true, + offsets = rec_get_offsets(rec, index, NULL, index->n_fields, ULINT_UNDEFINED, &heap); update = row_upd_build_sec_rec_difference_binary( rec, index, offsets, entry, heap); @@ -3934,7 +3934,8 @@ ibuf_delete( ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); - ut_ad(!dict_index_is_spatial(index)); + ut_ad(!index->is_spatial()); + ut_ad(!index->is_clust()); low_match = page_cur_search(block, index, entry, &page_cur); @@ -3953,8 +3954,8 @@ ibuf_delete( rec_offs_init(offsets_); - offsets = rec_get_offsets( - rec, index, offsets, true, ULINT_UNDEFINED, &heap); + offsets = rec_get_offsets(rec, index, offsets, index->n_fields, + ULINT_UNDEFINED, &heap); if (page_get_n_recs(page) <= 1 || !(REC_INFO_DELETED_FLAG diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h index 375b7b34fe4..943836f8759 100644 --- a/storage/innobase/include/btr0bulk.h +++ b/storage/innobase/include/btr0bulk.h @@ -314,6 +314,8 @@ public: /** Re-latch all latches */ void latch(); + table_name_t table_name() { return m_index->table->name; } + private: /** Insert a tuple to a page in a level @param[in] tuple tuple to insert diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index bc7afbf3b67..7facea7b80e 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -497,8 +497,10 @@ struct btr_pcur_t{ /** if cursor position is stored, contains an initial segment of the latest record cursor was positioned either on, before or after */ rec_t* old_rec; + /** btr_cur.index->n_core_fields when old_rec was copied */ + uint16 old_n_core_fields; /** number of fields in old_rec */ - ulint old_n_fields; + uint16 old_n_fields; /** BTR_PCUR_ON, BTR_PCUR_BEFORE, or BTR_PCUR_AFTER, depending on whether cursor was on, before, or after the old_rec record */ enum btr_pcur_pos_t rel_pos; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 1ad2517c8fb..c96ea8806df 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -2,7 +2,7 @@ Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -790,6 +790,35 @@ struct dict_v_col_t{ } }; +/** Data structure for newly added virtual column in a index. +It is used only during rollback_inplace_alter_table() of +addition of index depending on newly added virtual columns +and uses index heap. Should be freed when index is being +removed from cache. */ +struct dict_add_v_col_info +{ + ulint n_v_col; + dict_v_col_t *v_col; + + /** Add the newly added virtual column while rollbacking + the index which contains new virtual columns + @param col virtual column to be duplicated + @param offset offset where to duplicate virtual column */ + dict_v_col_t* add_drop_v_col(mem_heap_t *heap, dict_v_col_t *col, + ulint offset) + { + ut_ad(n_v_col); + ut_ad(offset < n_v_col); + if (!v_col) + v_col= static_cast<dict_v_col_t*> + (mem_heap_alloc(heap, n_v_col * sizeof *v_col)); + new (&v_col[offset]) dict_v_col_t(); + v_col[offset].m_col= col->m_col; + v_col[offset].v_pos= col->v_pos; + return &v_col[offset]; + } +}; + /** Data structure for newly added virtual column in a table */ struct dict_add_v_col_t{ /** number of new virtual column */ @@ -1037,9 +1066,12 @@ struct dict_index_t { dict_field_t* fields; /*!< array of field descriptions */ st_mysql_ftparser* parser; /*!< fulltext parser plugin */ - bool has_new_v_col; - /*!< whether it has a newly added virtual - column in ALTER */ + + /** It just indicates whether newly added virtual column + during alter. It stores column in case of alter failure. + It should use heap from dict_index_t. It should be freed + while removing the index from table. */ + dict_add_v_col_info* new_vcol_info; UT_LIST_NODE_T(dict_index_t) indexes;/*!< list of indexes of the table */ #ifdef BTR_CUR_ADAPT @@ -1199,9 +1231,8 @@ public: /** @return whether the index is corrupted */ inline bool is_corrupted() const; - /** Detach the virtual columns from the index that is to be removed. - @param whether to reset fields[].col */ - void detach_columns(bool clear= false) + /** Detach the virtual columns from the index that is to be removed. */ + void detach_columns() { if (!has_virtual() || !cached) return; @@ -1211,8 +1242,6 @@ public: if (!col || !col->is_virtual()) continue; col->detach(*this); - if (clear) - fields[i].col= nullptr; } } @@ -1275,6 +1304,23 @@ public: bool vers_history_row(const rec_t* rec, bool &history_row); + /** Assign the number of new column to be added as a part + of the index + @param n_vcol number of virtual columns to be added */ + void assign_new_v_col(ulint n_vcol) + { + new_vcol_info= static_cast<dict_add_v_col_info*> + (mem_heap_zalloc(heap, sizeof *new_vcol_info)); + new_vcol_info->n_v_col= n_vcol; + } + + /* @return whether index has new virtual column */ + bool has_new_v_col() const { return new_vcol_info; } + + /* @return number of newly added virtual column */ + ulint get_new_n_vcol() const + { return new_vcol_info ? new_vcol_info->n_v_col : 0; } + /** Reconstruct the clustered index fields. */ inline void reconstruct_fields(); @@ -2316,6 +2362,17 @@ public: /** mysql_row_templ_t for base columns used for compute the virtual columns */ dict_vcol_templ_t* vc_templ; + + /* @return whether the table has any other transcation lock + other than the given transaction */ + bool has_lock_other_than(const trx_t *trx) const + { + for (lock_t *lock= UT_LIST_GET_FIRST(locks); lock; + lock= UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock)) + if (lock->trx != trx) + return true; + return false; + } }; inline void dict_index_t::set_modified(mtr_t& mtr) const diff --git a/storage/innobase/include/gis0rtree.ic b/storage/innobase/include/gis0rtree.ic index 82747bdc95a..1b53caa306b 100644 --- a/storage/innobase/include/gis0rtree.ic +++ b/storage/innobase/include/gis0rtree.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -57,7 +57,8 @@ rtr_page_cal_mbr( page = buf_block_get_frame(block); rec = page_rec_get_next(page_get_infimum_rec(page)); - offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page), + offsets = rec_get_offsets(rec, index, offsets, page_is_leaf(page) + ? index->n_fields : 0, ULINT_UNDEFINED, &heap); do { diff --git a/storage/innobase/include/page0cur.ic b/storage/innobase/include/page0cur.ic index e8f7afcaf01..828be6840d2 100644 --- a/storage/innobase/include/page0cur.ic +++ b/storage/innobase/include/page0cur.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -273,7 +273,8 @@ page_cur_tuple_insert( index, tuple, n_ext); *offsets = rec_get_offsets(rec, index, *offsets, - page_is_leaf(cursor->block->frame), + page_is_leaf(cursor->block->frame) + ? index->n_core_fields : 0, ULINT_UNDEFINED, heap); ut_ad(size == rec_offs_size(*offsets)); diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index cda0d38ba44..dbcff3e6fd6 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -466,7 +466,7 @@ rec_get_n_extern_new( @param[in] index the index that the record belongs to @param[in,out] offsets array comprising offsets[0] allocated elements, or an array from rec_get_offsets(), or NULL -@param[in] leaf whether this is a leaf-page record +@param[in] n_core 0, or index->n_core_fields for leaf page @param[in] n_fields maximum number of offsets to compute (ULINT_UNDEFINED to compute all offsets) @param[in,out] heap memory heap @@ -476,7 +476,7 @@ rec_get_offsets_func( const rec_t* rec, const dict_index_t* index, rec_offs* offsets, - bool leaf, + ulint n_core, ulint n_fields, #ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ @@ -1082,7 +1082,9 @@ rec_get_converted_size( The fields are copied into the memory heap. @param[out] tuple data tuple @param[in] rec index record, or a copy thereof -@param[in] is_leaf whether rec is a leaf page record +@param[in] index index of rec +@param[in] n_core index->n_core_fields at the time rec was + copied, or 0 if non-leaf page record @param[in] n_fields number of fields to copy @param[in,out] heap memory heap */ void @@ -1090,7 +1092,7 @@ rec_copy_prefix_to_dtuple( dtuple_t* tuple, const rec_t* rec, const dict_index_t* index, - bool is_leaf, + ulint n_core, ulint n_fields, mem_heap_t* heap) MY_ATTRIBUTE((nonnull)); diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h index d9410298c01..1d7f9bb145b 100644 --- a/storage/innobase/include/row0merge.h +++ b/storage/innobase/include/row0merge.h @@ -167,18 +167,20 @@ row_merge_drop_indexes_dict( table_id_t table_id)/*!< in: table identifier */ MY_ATTRIBUTE((nonnull)); -/*********************************************************************//** -Drop those indexes which were created before an error occurred. +/** Drop indexes that were created before an error occurred. The data dictionary must have been locked exclusively by the caller, -because the transaction will not be committed. */ +because the transaction will not be committed. +@param trx dictionary transaction +@param table table containing the indexes +@param locked True if table is locked, + false - may need to do lazy drop +@param alter_trx Alter table transaction */ void row_merge_drop_indexes( -/*===================*/ - trx_t* trx, /*!< in/out: transaction */ - dict_table_t* table, /*!< in/out: table containing the indexes */ - ibool locked) /*!< in: TRUE=table locked, - FALSE=may need to do a lazy drop */ - MY_ATTRIBUTE((nonnull)); + trx_t* trx, + dict_table_t* table, + bool locked, + const trx_t* alter_trx=NULL); /*********************************************************************//** Drop all partially created indexes during crash recovery. */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 00da7d5fe82..43e5249a349 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4368,7 +4368,8 @@ static void lock_rec_print(FILE* file, const lock_t* lock, mtr_t& mtr) ut_ad(!page_rec_is_metadata(rec)); offsets = rec_get_offsets( - rec, lock->index, offsets, true, + rec, lock->index, offsets, + lock->index->n_core_fields, ULINT_UNDEFINED, &heap); putc(' ', file); @@ -4895,8 +4896,8 @@ loop: ut_ad(!lock_rec_get_nth_bit(lock, i) || page_rec_is_leaf(rec)); offsets = rec_get_offsets(rec, lock->index, offsets, - true, ULINT_UNDEFINED, - &heap); + lock->index->n_core_fields, + ULINT_UNDEFINED, &heap); /* If this thread is holding the file space latch (fil_space_t::latch), the following @@ -5207,7 +5208,8 @@ lock_rec_insert_check_and_lock( const rec_offs* offsets; rec_offs_init(offsets_); - offsets = rec_get_offsets(next_rec, index, offsets_, true, + offsets = rec_get_offsets(next_rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap); ut_ad(lock_rec_queue_validate( @@ -5545,7 +5547,8 @@ lock_sec_rec_modify_check_and_lock( const rec_offs* offsets; rec_offs_init(offsets_); - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap); ut_ad(lock_rec_queue_validate( @@ -5757,7 +5760,7 @@ lock_clust_rec_read_check_and_lock_alt( rec_offs_init(offsets_); ut_ad(page_rec_is_leaf(rec)); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &tmp_heap); err = lock_clust_rec_read_check_and_lock(flags, block, rec, index, offsets, mode, gap_mode, thr); diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index 5e751010f44..025d4b9b967 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -75,7 +75,7 @@ page_cur_try_search_shortcut( ut_ad(page_is_leaf(page)); rec = page_header_get_ptr(page, PAGE_LAST_INSERT); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, dtuple_get_n_fields(tuple), &heap); ut_ad(rec); @@ -90,7 +90,8 @@ page_cur_try_search_shortcut( next_rec = page_rec_get_next_const(rec); if (!page_rec_is_supremum(next_rec)) { - offsets = rec_get_offsets(next_rec, index, offsets, true, + offsets = rec_get_offsets(next_rec, index, offsets, + index->n_core_fields, dtuple_get_n_fields(tuple), &heap); if (cmp_dtuple_rec_with_match(tuple, next_rec, offsets, @@ -159,7 +160,7 @@ page_cur_try_search_shortcut_bytes( ut_ad(page_is_leaf(page)); rec = page_header_get_ptr(page, PAGE_LAST_INSERT); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, dtuple_get_n_fields(tuple), &heap); ut_ad(rec); @@ -180,7 +181,8 @@ page_cur_try_search_shortcut_bytes( next_rec = page_rec_get_next_const(rec); if (!page_rec_is_supremum(next_rec)) { - offsets = rec_get_offsets(next_rec, index, offsets, true, + offsets = rec_get_offsets(next_rec, index, offsets, + index->n_core_fields, dtuple_get_n_fields(tuple), &heap); if (cmp_dtuple_rec_with_match_bytes( @@ -321,14 +323,14 @@ page_cur_search_with_match( #endif /* UNIV_ZIP_DEBUG */ ut_d(page_check_dir(page)); - const bool is_leaf = page_is_leaf(page); + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; #ifdef BTR_CUR_HASH_ADAPT - if (is_leaf + if (n_core && page_get_direction(page) == PAGE_RIGHT && page_header_get_offs(page, PAGE_LAST_INSERT) && mode == PAGE_CUR_LE - && !dict_index_is_spatial(index) + && !index->is_spatial() && page_header_get_field(page, PAGE_N_DIRECTION) > 3 && page_cur_try_search_shortcut( block, index, tuple, @@ -344,10 +346,10 @@ page_cur_search_with_match( /* If the mode is for R-tree indexes, use the special MBR related compare functions */ - if (dict_index_is_spatial(index) && mode > PAGE_CUR_LE) { + if (index->is_spatial() && mode > PAGE_CUR_LE) { /* For leaf level insert, we still use the traditional compare function for now */ - if (mode == PAGE_CUR_RTREE_INSERT && is_leaf) { + if (mode == PAGE_CUR_RTREE_INSERT && n_core) { mode = PAGE_CUR_LE; } else { rtr_cur_search_with_match( @@ -392,7 +394,7 @@ page_cur_search_with_match( offsets = offsets_; offsets = rec_get_offsets( - mid_rec, index, offsets, is_leaf, + mid_rec, index, offsets, n_core, dtuple_get_n_fields_cmp(tuple), &heap); cmp = cmp_dtuple_rec_with_match( @@ -446,7 +448,7 @@ up_slot_match: offsets = offsets_; offsets = rec_get_offsets( - mid_rec, index, offsets, is_leaf, + mid_rec, index, offsets, n_core, dtuple_get_n_fields_cmp(tuple), &heap); cmp = cmp_dtuple_rec_with_match( @@ -627,7 +629,7 @@ page_cur_search_with_match_bytes( /* Perform binary search until the lower and upper limit directory slots come to the distance 1 of each other */ - const bool is_leaf = page_is_leaf(page); + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; while (up - low > 1) { mid = (low + up) / 2; @@ -639,7 +641,7 @@ page_cur_search_with_match_bytes( up_matched_fields, up_matched_bytes); offsets = rec_get_offsets( - mid_rec, index, offsets_, is_leaf, + mid_rec, index, offsets_, n_core, dtuple_get_n_fields_cmp(tuple), &heap); cmp = cmp_dtuple_rec_with_match_bytes( @@ -707,7 +709,7 @@ up_slot_match: } offsets = rec_get_offsets( - mid_rec, index, offsets_, is_leaf, + mid_rec, index, offsets_, n_core, dtuple_get_n_fields_cmp(tuple), &heap); cmp = cmp_dtuple_rec_with_match_bytes( @@ -1343,7 +1345,8 @@ page_cur_insert_rec_low( rec_offs_init(foffsets_); rec_offs *foffsets= rec_get_offsets(free_rec, index, foffsets_, - page_is_leaf(block->frame), + page_is_leaf(block->frame) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); const ulint fextra_size= rec_offs_extra_size(foffsets); insert_buf= free_rec - fextra_size; @@ -1838,7 +1841,8 @@ page_cur_insert_rec_zip( rec_offs *foffsets= rec_get_offsets(cursor->block->frame + free_rec, index, foffsets_, - page_is_leaf(cursor->block->frame), + page_is_leaf(cursor->block->frame) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap); insert_buf= cursor->block->frame + free_rec - rec_offs_extra_size(foffsets); diff --git a/storage/innobase/page/page0page.cc b/storage/innobase/page/page0page.cc index 5fe029d5b4d..9b83470e65c 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -482,7 +482,8 @@ page_copy_rec_list_end_no_locks( ut_a(page_is_comp(new_page) == page_rec_is_comp(rec)); ut_a(mach_read_from_2(new_page + srv_page_size - 10) == (ulint) (page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM)); - const bool is_leaf = page_is_leaf(block->frame); + const ulint n_core = page_is_leaf(block->frame) + ? index->n_core_fields : 0; page_cur_set_before_first(new_block, &cur2); @@ -490,7 +491,7 @@ page_copy_rec_list_end_no_locks( while (!page_cur_is_after_last(&cur1)) { rec_t* ins_rec; - offsets = rec_get_offsets(cur1.rec, index, offsets, is_leaf, + offsets = rec_get_offsets(cur1.rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); ins_rec = page_cur_insert_rec_low(&cur2, index, cur1.rec, offsets, mtr); @@ -721,7 +722,7 @@ page_copy_rec_list_start( page_cur_position(ret, new_block, &cur2); - const bool is_leaf = page_rec_is_leaf(rec); + const ulint n_core = page_rec_is_leaf(rec) ? index->n_core_fields : 0; /* Copy records from the original page to the new page */ if (index->is_spatial()) { @@ -743,7 +744,7 @@ page_copy_rec_list_start( } else { while (page_cur_get_rec(&cur1) != rec) { offsets = rec_get_offsets(cur1.rec, index, offsets, - is_leaf, + n_core, ULINT_UNDEFINED, &heap); cur2.rec = page_cur_insert_rec_low(&cur2, index, cur1.rec, offsets, @@ -764,7 +765,7 @@ page_copy_rec_list_start( same temp-table in parallel. max_trx_id is ignored for temp tables because it not required for MVCC. */ - if (is_leaf && dict_index_is_sec_or_ibuf(index) + if (n_core && dict_index_is_sec_or_ibuf(index) && !index->table->is_temporary()) { page_update_max_trx_id(new_block, new_page_zip, @@ -884,10 +885,10 @@ page_delete_rec_list_end( } #endif - /* The page gets invalid for optimistic searches */ + /* The page becomes invalid for optimistic searches */ buf_block_modify_clock_inc(block); - const bool is_leaf= page_is_leaf(block->frame); + const ulint n_core= page_is_leaf(block->frame) ? index->n_core_fields : 0; mem_heap_t *heap= nullptr; rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs *offsets= offsets_; @@ -901,7 +902,7 @@ page_delete_rec_list_end( { page_cur_t cur; page_cur_position(rec, block, &cur); - offsets= rec_get_offsets(rec, index, offsets, is_leaf, + offsets= rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); rec= rec_get_next_ptr(rec, TRUE); #ifdef UNIV_ZIP_DEBUG @@ -932,7 +933,7 @@ page_delete_rec_list_end( do { - offsets = rec_get_offsets(rec2, index, offsets, is_leaf, + offsets = rec_get_offsets(rec2, index, offsets, n_core, ULINT_UNDEFINED, &heap); ulint s= rec_offs_size(offsets); ut_ad(ulint(rec2 - block->frame) + s - rec_offs_extra_size(offsets) < @@ -1097,11 +1098,12 @@ page_delete_rec_list_start( page_cur_set_before_first(block, &cur1); page_cur_move_to_next(&cur1); - const bool is_leaf = page_rec_is_leaf(rec); + const ulint n_core = page_rec_is_leaf(rec) + ? index->n_core_fields : 0; while (page_cur_get_rec(&cur1) != rec) { offsets = rec_get_offsets(page_cur_get_rec(&cur1), index, - offsets, is_leaf, + offsets, n_core, ULINT_UNDEFINED, &heap); page_cur_delete_rec(&cur1, index, offsets, mtr); } @@ -2104,9 +2106,10 @@ wrong_page_type: rec = page_get_infimum_rec(page); + const ulint n_core = page_is_leaf(page) ? index->n_core_fields : 0; + for (;;) { - offsets = rec_get_offsets(rec, index, offsets, - page_is_leaf(page), + offsets = rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); if (page_is_comp(page) && page_rec_is_user_rec(rec) @@ -2352,8 +2355,7 @@ n_owned_zero: rec = page_header_get_ptr(page, PAGE_FREE); while (rec != NULL) { - offsets = rec_get_offsets(rec, index, offsets, - page_is_leaf(page), + offsets = rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); if (UNIV_UNLIKELY(!page_rec_validate(rec, offsets))) { ret = FALSE; diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 2c8b0cf5136..1ed9efafc69 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -2,7 +2,7 @@ Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2014, 2020, MariaDB Corporation. +Copyright (c) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -903,7 +903,7 @@ page_zip_compress_node_ptrs( do { const rec_t* rec = *recs++; - offsets = rec_get_offsets(rec, index, offsets, false, + offsets = rec_get_offsets(rec, index, offsets, 0, ULINT_UNDEFINED, &heap); /* Only leaf nodes may contain externally stored columns. */ ut_ad(!rec_offs_any_extern(offsets)); @@ -1152,7 +1152,7 @@ page_zip_compress_clust( do { const rec_t* rec = *recs++; - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_fields, ULINT_UNDEFINED, &heap); ut_ad(rec_offs_n_fields(offsets) == dict_index_get_n_fields(index)); @@ -2027,7 +2027,7 @@ page_zip_apply_log( sorted by address (indexed by heap_no - PAGE_HEAP_NO_USER_LOW) */ ulint n_dense,/*!< in: size of recs[] */ - bool is_leaf,/*!< in: whether this is a leaf page */ + ulint n_core, /*!< in: index->n_fields, or 0 for non-leaf */ ulint trx_id_col,/*!< in: column number of trx_id in the index, or ULINT_UNDEFINED if none */ ulint heap_status, @@ -2103,7 +2103,7 @@ page_zip_apply_log( /* Clear the data bytes of the record. */ mem_heap_t* heap = NULL; rec_offs* offs; - offs = rec_get_offsets(rec, index, offsets, is_leaf, + offs = rec_get_offsets(rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); memset(rec, 0, rec_offs_data_size(offs)); @@ -2121,7 +2121,7 @@ page_zip_apply_log( This will be overwritten in page_zip_set_extra_bytes(), called by page_zip_decompress_low(). */ ut_d(rec[-REC_NEW_INFO_BITS] = 0); - rec_offs_make_valid(rec, index, is_leaf, offsets); + rec_offs_make_valid(rec, index, n_core != 0, offsets); /* Copy the extra bytes (backwards). */ { @@ -2301,7 +2301,7 @@ page_zip_decompress_node_ptrs( } /* Read the offsets. The status bits are needed here. */ - offsets = rec_get_offsets(rec, index, offsets, false, + offsets = rec_get_offsets(rec, index, offsets, 0, ULINT_UNDEFINED, &heap); /* Non-leaf nodes should not have any externally @@ -2388,7 +2388,7 @@ zlib_done: const byte* mod_log_ptr; mod_log_ptr = page_zip_apply_log(d_stream->next_in, d_stream->avail_in + 1, - recs, n_dense, false, + recs, n_dense, 0, ULINT_UNDEFINED, heap_status, index, offsets); @@ -2419,7 +2419,7 @@ zlib_done: for (slot = 0; slot < n_dense; slot++) { rec_t* rec = recs[slot]; - offsets = rec_get_offsets(rec, index, offsets, false, + offsets = rec_get_offsets(rec, index, offsets, 0, ULINT_UNDEFINED, &heap); /* Non-leaf nodes should not have any externally stored columns. */ @@ -2541,7 +2541,8 @@ zlib_done: const byte* mod_log_ptr; mod_log_ptr = page_zip_apply_log(d_stream->next_in, d_stream->avail_in + 1, - recs, n_dense, true, + recs, n_dense, + index->n_fields, ULINT_UNDEFINED, heap_status, index, offsets); @@ -2744,7 +2745,7 @@ page_zip_decompress_clust( } /* Read the offsets. The status bits are needed here. */ - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_fields, ULINT_UNDEFINED, &heap); /* This is a leaf page in a clustered index. */ @@ -2871,7 +2872,8 @@ zlib_done: const byte* mod_log_ptr; mod_log_ptr = page_zip_apply_log(d_stream->next_in, d_stream->avail_in + 1, - recs, n_dense, true, + recs, n_dense, + index->n_fields, trx_id_col, heap_status, index, offsets); @@ -2907,7 +2909,7 @@ zlib_done: rec_t* rec = recs[slot]; bool exists = !page_zip_dir_find_free( page_zip, page_offset(rec)); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_fields, ULINT_UNDEFINED, &heap); dst = rec_get_nth_field(rec, offsets, @@ -3430,7 +3432,7 @@ page_zip_validate_low( page + PAGE_NEW_INFIMUM, TRUE); trec = page_rec_get_next_low( temp_page + PAGE_NEW_INFIMUM, TRUE); - const bool is_leaf = page_is_leaf(page); + const ulint n_core = page_is_leaf(page) ? index->n_fields : 0; do { if (page_offset(rec) != page_offset(trec)) { @@ -3445,7 +3447,7 @@ page_zip_validate_low( if (index) { /* Compare the data. */ offsets = rec_get_offsets( - rec, index, offsets, is_leaf, + rec, index, offsets, n_core, ULINT_UNDEFINED, &heap); if (memcmp(rec - rec_offs_extra_size(offsets), diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index aae621b6f56..419727b4d37 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -273,9 +273,9 @@ rec_init_offsets_comp_ordinary( ulint n_fields = n_core; ulint null_mask = 1; - ut_ad(index->n_core_fields >= n_core); ut_ad(n_core > 0); - ut_ad(index->n_fields >= n_core); + ut_ad(index->n_core_fields >= n_core); + ut_ad(index->n_fields >= index->n_core_fields); ut_ad(index->n_core_null_bytes <= UT_BITS_IN_BYTES(index->n_nullable)); ut_ad(format == REC_LEAF_TEMP || format == REC_LEAF_TEMP_INSTANT || dict_table_is_comp(index->table)); @@ -283,6 +283,11 @@ rec_init_offsets_comp_ordinary( || index->n_fields == rec_offs_n_fields(offsets)); ut_d(ulint n_null= 0); + const unsigned n_core_null_bytes = UNIV_UNLIKELY(index->n_core_fields + != n_core) + ? UT_BITS_IN_BYTES(unsigned(index->get_n_nullable(n_core))) + : index->n_core_null_bytes; + if (mblob) { ut_ad(index->table->instant); ut_ad(index->is_instant()); @@ -297,7 +302,7 @@ rec_init_offsets_comp_ordinary( const ulint n_null_bytes = UT_BITS_IN_BYTES(n_nullable); ut_d(n_null = n_nullable); ut_ad(n_null <= index->n_nullable); - ut_ad(n_null_bytes >= index->n_core_null_bytes + ut_ad(n_null_bytes >= n_core_null_bytes || n_core < index->n_core_fields); lens = --nulls - n_null_bytes; goto start; @@ -314,10 +319,10 @@ rec_init_offsets_comp_ordinary( case REC_LEAF_ORDINARY: nulls -= REC_N_NEW_EXTRA_BYTES; ordinary: - lens = --nulls - index->n_core_null_bytes; + lens = --nulls - n_core_null_bytes; - ut_d(n_null = std::min<uint>(index->n_core_null_bytes * 8U, - index->n_nullable)); + ut_d(n_null = std::min(n_core_null_bytes * 8U, + index->n_nullable)); break; case REC_LEAF_INSTANT: nulls -= REC_N_NEW_EXTRA_BYTES; @@ -330,7 +335,7 @@ ordinary: const ulint n_null_bytes = UT_BITS_IN_BYTES(n_nullable); ut_d(n_null = n_nullable); ut_ad(n_null <= index->n_nullable); - ut_ad(n_null_bytes >= index->n_core_null_bytes + ut_ad(n_null_bytes >= n_core_null_bytes || n_core < index->n_core_fields); lens = --nulls - n_null_bytes; } @@ -588,14 +593,14 @@ is (SQL_NULL), the field i is NULL. When the type of the offset at [i+1] is (STORED_OFFPAGE), the field i is stored externally. @param[in] rec record @param[in] index the index that the record belongs in -@param[in] leaf whether the record resides in a leaf page +@param[in] n_core 0, or index->n_core_fields for leaf page @param[in,out] offsets array of offsets, with valid rec_offs_n_fields() */ static void rec_init_offsets( const rec_t* rec, const dict_index_t* index, - bool leaf, + ulint n_core, rec_offs* offsets) { ulint i = 0; @@ -610,6 +615,8 @@ rec_init_offsets( || index->in_instant_init); ut_d(memcpy(&offsets[RECORD_OFFSET], &rec, sizeof(rec))); ut_d(memcpy(&offsets[INDEX_OFFSET], &index, sizeof(index))); + ut_ad(index->n_fields >= n_core); + ut_ad(index->n_core_fields >= n_core); if (dict_table_is_comp(index->table)) { const byte* nulls; @@ -628,23 +635,21 @@ rec_init_offsets( rec_offs_base(offsets)[1] = 8; return; case REC_STATUS_NODE_PTR: - ut_ad(!leaf); + ut_ad(!n_core); n_node_ptr_field = dict_index_get_n_unique_in_tree_nonleaf( index); break; case REC_STATUS_INSTANT: - ut_ad(leaf); ut_ad(index->is_instant()); rec_init_offsets_comp_ordinary(rec, index, offsets, - index->n_core_fields, + n_core, NULL, REC_LEAF_INSTANT); return; case REC_STATUS_ORDINARY: - ut_ad(leaf); rec_init_offsets_comp_ordinary(rec, index, offsets, - index->n_core_fields, + n_core, NULL, REC_LEAF_ORDINARY); return; @@ -806,7 +811,7 @@ resolved: @param[in] index the index that the record belongs to @param[in,out] offsets array comprising offsets[0] allocated elements, or an array from rec_get_offsets(), or NULL -@param[in] leaf whether this is a leaf-page record +@param[in] n_core 0, or index->n_core_fields for leaf page @param[in] n_fields maximum number of offsets to compute (ULINT_UNDEFINED to compute all offsets) @param[in,out] heap memory heap @@ -816,7 +821,7 @@ rec_get_offsets_func( const rec_t* rec, const dict_index_t* index, rec_offs* offsets, - bool leaf, + ulint n_core, ulint n_fields, #ifdef UNIV_DEBUG const char* file, /*!< in: file name where called */ @@ -828,6 +833,15 @@ rec_get_offsets_func( ulint size; bool alter_metadata = false; + ut_ad(index->n_core_fields >= n_core); + /* This assertion was relaxed for the btr_cur_open_at_index_side() + call in btr_cur_instant_init_low(). We cannot invoke + index->is_instant(), because the same assertion would fail there + until btr_cur_instant_init_low() has invoked + dict_table_t::deserialise_columns(). */ + ut_ad(index->n_fields >= index->n_core_fields + || index->in_instant_init); + if (dict_table_is_comp(index->table)) { switch (UNIV_EXPECT(rec_get_status(rec), REC_STATUS_ORDINARY)) { @@ -835,14 +849,14 @@ rec_get_offsets_func( alter_metadata = rec_is_alter_metadata(rec, true); /* fall through */ case REC_STATUS_ORDINARY: - ut_ad(leaf); + ut_ad(n_core); n = dict_index_get_n_fields(index) + alter_metadata; break; case REC_STATUS_NODE_PTR: /* Node pointer records consist of the uniquely identifying fields of the record followed by a child page number field. */ - ut_ad(!leaf); + ut_ad(!n_core); n = dict_index_get_n_unique_in_tree_nonleaf(index) + 1; break; case REC_STATUS_INFIMUM: @@ -871,19 +885,19 @@ rec_get_offsets_func( >= PAGE_HEAP_NO_USER_LOW; /* The infimum and supremum records carry 1 field. */ ut_ad(is_user_rec || n == 1); - ut_ad(!is_user_rec || leaf || index->is_dummy + ut_ad(!is_user_rec || n_core || index->is_dummy || dict_index_is_ibuf(index) || n == n_fields /* dict_stats_analyze_index_level() */ || n - 1 == dict_index_get_n_unique_in_tree_nonleaf(index)); - ut_ad(!is_user_rec || !leaf || index->is_dummy + ut_ad(!is_user_rec || !n_core || index->is_dummy || dict_index_is_ibuf(index) || n == n_fields /* btr_pcur_restore_position() */ || (n + (index->id == DICT_INDEXES_ID) - >= index->n_core_fields && n <= index->n_fields + >= n_core && n <= index->n_fields + unsigned(rec_is_alter_metadata(rec, false)))); - if (is_user_rec && leaf && n < index->n_fields) { + if (is_user_rec && n_core && n < index->n_fields) { ut_ad(!index->is_dummy); ut_ad(!dict_index_is_ibuf(index)); n = index->n_fields; @@ -917,17 +931,17 @@ rec_get_offsets_func( memcpy(&offsets[RECORD_OFFSET], &rec, sizeof rec); memcpy(&offsets[INDEX_OFFSET], &index, sizeof index); #endif /* UNIV_DEBUG */ - ut_ad(leaf); + ut_ad(n_core); ut_ad(index->table->instant); ut_ad(index->is_instant()); ut_ad(rec_offs_n_fields(offsets) <= ulint(index->n_fields) + 1); rec_init_offsets_comp_ordinary<true>(rec, index, offsets, index->n_core_fields, - NULL, + nullptr, REC_LEAF_INSTANT); } else { - rec_init_offsets(rec, index, leaf, offsets); + rec_init_offsets(rec, index, n_core, offsets); } return offsets; } @@ -1850,7 +1864,9 @@ template void rec_convert_dtuple_to_temp<true>( The fields are copied into the memory heap. @param[out] tuple data tuple @param[in] rec index record, or a copy thereof -@param[in] is_leaf whether rec is a leaf page record +@param[in] index index of rec +@param[in] n_core index->n_core_fields at the time rec was + copied, or 0 if non-leaf page record @param[in] n_fields number of fields to copy @param[in,out] heap memory heap */ void @@ -1858,7 +1874,7 @@ rec_copy_prefix_to_dtuple( dtuple_t* tuple, const rec_t* rec, const dict_index_t* index, - bool is_leaf, + ulint n_core, ulint n_fields, mem_heap_t* heap) { @@ -1866,10 +1882,11 @@ rec_copy_prefix_to_dtuple( rec_offs* offsets = offsets_; rec_offs_init(offsets_); - ut_ad(is_leaf || n_fields - 1 + ut_ad(n_core <= index->n_core_fields); + ut_ad(n_core || n_fields - 1 <= dict_index_get_n_unique_in_tree_nonleaf(index)); - offsets = rec_get_offsets(rec, index, offsets, is_leaf, + offsets = rec_get_offsets(rec, index, offsets, n_core, n_fields, &heap); ut_ad(rec_validate(rec, offsets)); @@ -2509,7 +2526,8 @@ rec_print( rec_print_new(file, rec, rec_get_offsets(rec, index, offsets_, - page_rec_is_leaf(rec), + page_rec_is_leaf(rec) + ? index->n_core_fields : 0, ULINT_UNDEFINED, &heap)); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); @@ -2585,7 +2603,8 @@ operator<<(std::ostream& o, const rec_index_print& r) { mem_heap_t* heap = NULL; rec_offs* offsets = rec_get_offsets( - r.m_rec, r.m_index, NULL, page_rec_is_leaf(r.m_rec), + r.m_rec, r.m_index, NULL, page_rec_is_leaf(r.m_rec) + ? r.m_index->n_core_fields : 0, ULINT_UNDEFINED, &heap); rec_print(o, r.m_rec, rec_get_info_bits(r.m_rec, rec_offs_comp(offsets)), @@ -2624,7 +2643,7 @@ rec_get_trx_id( rec_offs_init(offsets_); rec_offs* offsets = offsets_; - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, index->db_trx_id() + 1, &heap); trx_id = rec_get_nth_field(rec, offsets, index->db_trx_id(), &len); @@ -2675,7 +2694,8 @@ wsrep_rec_get_foreign_key( ut_ad(index_ref); rec_offs_init(offsets_); - offsets = rec_get_offsets(rec, index_for, offsets_, true, + offsets = rec_get_offsets(rec, index_for, offsets_, + index_for->n_core_fields, ULINT_UNDEFINED, &heap); ut_ad(rec_offs_validate(rec, NULL, offsets)); diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index baf63650347..562395e3e80 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -909,7 +909,7 @@ loop: << " records, the sort queue has " << UT_LIST_GET_LEN(psort_info->fts_doc_list) << " records. But sort cannot get the next" - " records"; + " records during alter table " << table->name; goto exit; } } else if (psort_info->state == FTS_PARENT_EXITING) { @@ -1190,7 +1190,9 @@ row_merge_write_fts_word( if (UNIV_UNLIKELY(error != DB_SUCCESS)) { ib::error() << "Failed to write word to FTS auxiliary" - " index table, error " << error; + " index table " + << ins_ctx->btr_bulk->table_name() + << ", error " << error; ret = error; } diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 4e05649c56a..9ffbe41ed11 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -1839,7 +1839,8 @@ PageConverter::update_records( if (deleted || clust_index) { m_offsets = rec_get_offsets( - rec, m_index->m_srv_index, m_offsets, true, + rec, m_index->m_srv_index, m_offsets, + m_index->m_srv_index->n_core_fields, ULINT_UNDEFINED, &m_heap); } diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 4aed14cc059..77d2fdfd171 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2020, MariaDB Corporation. +Copyright (c) 2016, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -881,7 +881,7 @@ row_ins_foreign_fill_virtual( rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_); const rec_offs* offsets = - rec_get_offsets(rec, index, offsets_, true, + rec_get_offsets(rec, index, offsets_, index->n_core_fields, ULINT_UNDEFINED, &cascade->heap); TABLE* mysql_table= NULL; upd_t* update = cascade->update; @@ -1195,7 +1195,8 @@ row_ins_foreign_check_on_constraint( if (table->fts) { doc_id = fts_get_doc_id_from_rec( clust_rec, clust_index, - rec_get_offsets(clust_rec, clust_index, NULL, true, + rec_get_offsets(clust_rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &tmp_heap)); } @@ -1638,7 +1639,8 @@ row_ins_check_foreign_constraint( continue; } - offsets = rec_get_offsets(rec, check_index, offsets, true, + offsets = rec_get_offsets(rec, check_index, offsets, + check_index->n_core_fields, ULINT_UNDEFINED, &heap); if (page_rec_is_supremum(rec)) { @@ -2126,7 +2128,8 @@ row_ins_scan_sec_index_for_duplicate( continue; } - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &offsets_heap); if (flags & BTR_NO_LOCKING_FLAG) { @@ -2263,7 +2266,8 @@ row_ins_duplicate_error_in_clust_online( ut_ad(!cursor->index->is_instant()); if (cursor->low_match >= n_uniq && !page_rec_is_infimum(rec)) { - *offsets = rec_get_offsets(rec, cursor->index, *offsets, true, + *offsets = rec_get_offsets(rec, cursor->index, *offsets, + cursor->index->n_fields, ULINT_UNDEFINED, heap); err = row_ins_duplicate_online(n_uniq, entry, rec, *offsets); if (err != DB_SUCCESS) { @@ -2274,7 +2278,8 @@ row_ins_duplicate_error_in_clust_online( rec = page_rec_get_next_const(btr_cur_get_rec(cursor)); if (cursor->up_match >= n_uniq && !page_rec_is_supremum(rec)) { - *offsets = rec_get_offsets(rec, cursor->index, *offsets, true, + *offsets = rec_get_offsets(rec, cursor->index, *offsets, + cursor->index->n_fields, ULINT_UNDEFINED, heap); err = row_ins_duplicate_online(n_uniq, entry, rec, *offsets); } @@ -2330,7 +2335,7 @@ row_ins_duplicate_error_in_clust( if (!page_rec_is_infimum(rec)) { offsets = rec_get_offsets(rec, cursor->index, offsets, - true, + cursor->index->n_core_fields, ULINT_UNDEFINED, &heap); /* We set a lock on the possible duplicate: this @@ -2396,7 +2401,7 @@ duplicate: if (!page_rec_is_supremum(rec)) { offsets = rec_get_offsets(rec, cursor->index, offsets, - true, + cursor->index->n_core_fields, ULINT_UNDEFINED, &heap); if (trx->duplicates) { @@ -2513,7 +2518,7 @@ row_ins_index_entry_big_rec( btr_pcur_open(index, entry, PAGE_CUR_LE, BTR_MODIFY_TREE, &pcur, &mtr); rec = btr_pcur_get_rec(&pcur); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, heap); DEBUG_SYNC_C_IF_THD(thd, "before_row_ins_extern"); @@ -3068,7 +3073,8 @@ row_ins_sec_index_entry_low( prefix, we must convert the insert into a modify of an existing record */ offsets = rec_get_offsets( - btr_cur_get_rec(&cursor), index, offsets, true, + btr_cur_get_rec(&cursor), index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &offsets_heap); err = row_ins_sec_index_entry_by_modify( diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 699c9d80694..336b5a27cc2 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -1258,7 +1258,8 @@ row_log_table_get_pk( if (!offsets) { offsets = rec_get_offsets( - rec, index, NULL, true, + rec, index, nullptr, + index->n_core_fields, index->db_trx_id() + 1, heap); } @@ -1308,7 +1309,8 @@ row_log_table_get_pk( } if (!offsets) { - offsets = rec_get_offsets(rec, index, NULL, true, + offsets = rec_get_offsets(rec, index, nullptr, + index->n_core_fields, ULINT_UNDEFINED, heap); } @@ -1985,7 +1987,8 @@ all_done: return(DB_SUCCESS); } - offsets = rec_get_offsets(btr_pcur_get_rec(&pcur), index, NULL, true, + offsets = rec_get_offsets(btr_pcur_get_rec(&pcur), index, nullptr, + index->n_core_fields, ULINT_UNDEFINED, &offsets_heap); #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG ut_a(!rec_offs_any_null_extern(btr_pcur_get_rec(&pcur), offsets)); @@ -2182,7 +2185,7 @@ func_exit_committed: /* Prepare to update (or delete) the record. */ rec_offs* cur_offsets = rec_get_offsets( - btr_pcur_get_rec(&pcur), index, NULL, true, + btr_pcur_get_rec(&pcur), index, nullptr, index->n_core_fields, ULINT_UNDEFINED, &offsets_heap); if (!log->same_pk) { diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 44ab3e8d791..26f3a9debb7 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2005, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2014, 2020, MariaDB Corporation. +Copyright (c) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2022,7 +2022,8 @@ end_of_index: rec = page_cur_get_rec(cur); if (online) { - offsets = rec_get_offsets(rec, clust_index, NULL, true, + offsets = rec_get_offsets(rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &row_heap); rec_trx_id = row_get_rec_trx_id(rec, clust_index, offsets); @@ -2114,7 +2115,8 @@ end_of_index: duplicate keys. */ continue; } else { - offsets = rec_get_offsets(rec, clust_index, NULL, true, + offsets = rec_get_offsets(rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &row_heap); /* This is a locking ALTER TABLE. @@ -3782,17 +3784,20 @@ row_merge_drop_indexes_dict( trx->op_info = ""; } -/*********************************************************************//** -Drop indexes that were created before an error occurred. +/** Drop indexes that were created before an error occurred. The data dictionary must have been locked exclusively by the caller, -because the transaction will not be committed. */ +because the transaction will not be committed. +@param trx dictionary transaction +@param table table containing the indexes +@param locked True if table is locked, + false - may need to do lazy drop +@param alter_trx Alter table transaction */ void row_merge_drop_indexes( -/*===================*/ - trx_t* trx, /*!< in/out: dictionary transaction */ - dict_table_t* table, /*!< in/out: table containing the indexes */ - ibool locked) /*!< in: TRUE=table locked, - FALSE=may need to do a lazy drop */ + trx_t* trx, + dict_table_t* table, + bool locked, + const trx_t* alter_trx) { dict_index_t* index; dict_index_t* next_index; @@ -3817,7 +3822,7 @@ row_merge_drop_indexes( A concurrent purge will be prevented by dict_sys.latch. */ if (!locked && (table->get_ref_count() > 1 - || UT_LIST_GET_FIRST(table->locks))) { + || table->has_lock_other_than(alter_trx))) { /* We will have to drop the indexes later, when the table is guaranteed to be no longer in use. Mark the indexes as incomplete and corrupted, so that other @@ -4246,6 +4251,7 @@ row_merge_create_index( dict_index_t* index; ulint n_fields = index_def->n_fields; ulint i; + ulint n_add_vcol = 0; DBUG_ENTER("row_merge_create_index"); @@ -4270,7 +4276,7 @@ row_merge_create_index( ut_ad(ifield->col_no >= table->n_v_def); name = add_v->v_col_name[ ifield->col_no - table->n_v_def]; - index->has_new_v_col = true; + n_add_vcol++; } else { name = dict_table_get_v_col_name( table, ifield->col_no); @@ -4282,6 +4288,10 @@ row_merge_create_index( dict_mem_index_add_field(index, name, ifield->prefix_len); } + if (n_add_vcol) { + index->assign_new_v_col(n_add_vcol); + } + DBUG_RETURN(index); } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 9e374ab5c6e..ce0746f20c6 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -688,6 +688,7 @@ row_mysql_handle_errors( dberr_t err; DBUG_ENTER("row_mysql_handle_errors"); + DEBUG_SYNC_C("row_mysql_handle_errors"); handle_new_error: err = trx->error_state; @@ -1800,12 +1801,11 @@ row_update_for_mysql(row_prebuilt_t* prebuilt) clust_index = dict_table_get_first_index(table); - if (prebuilt->pcur->btr_cur.index == clust_index) { - btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur); - } else { - btr_pcur_copy_stored_position(node->pcur, - prebuilt->clust_pcur); - } + btr_pcur_copy_stored_position(node->pcur, + prebuilt->pcur->btr_cur.index + == clust_index + ? prebuilt->pcur + : prebuilt->clust_pcur); ut_a(node->pcur->rel_pos == BTR_PCUR_ON); @@ -2014,7 +2014,8 @@ row_unlock_for_mysql( rec_offs* offsets = offsets_; rec_offs_init(offsets_); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); rec_trx_id = row_get_rec_trx_id(rec, index, offsets); @@ -4789,7 +4790,7 @@ func_exit: rec = buf + mach_read_from_4(buf); - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, index->n_core_fields, ULINT_UNDEFINED, &heap); if (prev_entry != NULL) { diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index cad70a2c6eb..7a2971493f6 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -136,8 +136,9 @@ row_purge_remove_clust_if_poss_low( rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_); mem_heap_t* heap = NULL; - rec_offs* offsets = rec_get_offsets( - rec, index, offsets_, true, ULINT_UNDEFINED, &heap); + rec_offs* offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, + ULINT_UNDEFINED, &heap); bool success = true; if (node->roll_ptr != row_get_rec_roll_ptr(rec, index, offsets)) { @@ -616,7 +617,7 @@ row_purge_skip_uncommitted_virtual_index( not support LOCK=NONE when adding an index on newly added virtual column.*/ while (index != NULL && dict_index_has_virtual(index) - && !index->is_committed() && index->has_new_v_col) { + && !index->is_committed() && index->has_new_v_col()) { index = dict_table_get_next_index(index); } } @@ -682,7 +683,8 @@ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr) rec_offs offsets_[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS + 2]; rec_offs_init(offsets_); rec_offs* offsets = rec_get_offsets( - rec, index, offsets_, true, trx_id_pos + 2, &heap); + rec, index, offsets_, index->n_core_fields, + trx_id_pos + 2, &heap); ut_ad(heap == NULL); ut_ad(dict_index_get_nth_field(index, trx_id_pos) @@ -1214,7 +1216,7 @@ purge_node_t::validate_pcur() dict_index_t* clust_index = pcur.btr_cur.index; rec_offs* offsets = rec_get_offsets( - pcur.old_rec, clust_index, NULL, true, + pcur.old_rec, clust_index, NULL, pcur.old_n_core_fields, pcur.old_n_fields, &heap); /* Here we are comparing the purge ref record and the stored initial diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index 39cefb463e4..7e70341a20e 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2020, MariaDB Corporation. +Copyright (c) 2018, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -440,7 +440,8 @@ row_build_low( ut_ad(!col_map || col_table); if (!offsets) { - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &tmp_heap); } else { ut_ad(rec_offs_validate(rec, index, offsets)); @@ -1004,7 +1005,7 @@ row_build_row_ref( ut_ad(heap != NULL); ut_ad(!dict_index_is_clust(index)); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &tmp_heap); /* Secondary indexes must not contain externally stored columns. */ ut_ad(!rec_offs_any_extern(offsets)); @@ -1113,7 +1114,8 @@ row_build_row_ref_in_tuple( ut_ad(clust_index); if (!offsets) { - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap); } else { ut_ad(rec_offs_validate(rec, index, offsets)); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 99e8cce1572..aaac86c93e2 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -203,9 +203,11 @@ row_sel_sec_rec_is_for_clust_rec( ib_vcol_row vc(heap); clust_offs = rec_get_offsets(clust_rec, clust_index, clust_offs, - true, ULINT_UNDEFINED, &heap); + clust_index->n_core_fields, + ULINT_UNDEFINED, &heap); sec_offs = rec_get_offsets(sec_rec, sec_index, sec_offs, - true, ULINT_UNDEFINED, &heap); + sec_index->n_fields, + ULINT_UNDEFINED, &heap); n = dict_index_get_n_ordering_defined_by_user(sec_index); @@ -908,7 +910,9 @@ row_sel_get_clust_rec( offsets = rec_get_offsets(rec, btr_pcur_get_btr_cur(&plan->pcur)->index, - offsets, true, ULINT_UNDEFINED, &heap); + offsets, + btr_pcur_get_btr_cur(&plan->pcur)->index + ->n_core_fields, ULINT_UNDEFINED, &heap); row_build_row_ref_fast(plan->clust_ref, plan->clust_map, rec, offsets); @@ -943,7 +947,8 @@ row_sel_get_clust_rec( goto err_exit; } - offsets = rec_get_offsets(clust_rec, index, offsets, true, + offsets = rec_get_offsets(clust_rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); if (!node->read_view) { @@ -1153,7 +1158,8 @@ re_scan: rec = btr_pcur_get_rec(pcur); my_offsets = offsets_; - my_offsets = rec_get_offsets(rec, index, my_offsets, true, + my_offsets = rec_get_offsets(rec, index, my_offsets, + index->n_fields, ULINT_UNDEFINED, &heap); /* No match record */ @@ -1176,7 +1182,7 @@ re_scan: rtr_rec_t* rtr_rec = &(*it); my_offsets = rec_get_offsets( - rtr_rec->r_rec, index, my_offsets, true, + rtr_rec->r_rec, index, my_offsets, index->n_fields, ULINT_UNDEFINED, &heap); err = lock_sec_rec_read_check_and_lock( @@ -1483,7 +1489,7 @@ exhausted: rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs* offsets = offsets_; rec_offs_init(offsets_); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); if (dict_index_is_clust(index)) { @@ -1699,7 +1705,7 @@ rec_loop: trx = thr_get_trx(thr); offsets = rec_get_offsets(next_rec, index, offsets, - true, + index->n_core_fields, ULINT_UNDEFINED, &heap); /* At READ UNCOMMITTED or READ COMMITTED @@ -1759,7 +1765,8 @@ skip_lock: unsigned lock_type; trx_t* trx; - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); trx = thr_get_trx(thr); @@ -1844,7 +1851,7 @@ skip_lock: /* PHASE 3: Get previous version in a consistent read */ cons_read_requires_clust_rec = FALSE; - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); if (consistent_read) { @@ -1875,7 +1882,8 @@ skip_lock: exhausted. */ offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); /* Fetch the columns needed in @@ -3179,7 +3187,8 @@ class Row_sel_get_clust_rec_for_mysql ut_ad(rec_offs_validate(cached_clust_rec, index, offsets)); ut_ad(index->first_user_field() <= rec_offs_n_fields(offsets)); - ut_ad(vers_offs == rec_get_offsets(cached_old_vers, index, vers_offs, true, + ut_ad(vers_offs == rec_get_offsets(cached_old_vers, index, vers_offs, + index->n_core_fields, index->db_trx_id(), &heap)); ut_ad(!heap); for (auto n= index->db_trx_id(); n--; ) @@ -3366,7 +3375,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( goto func_exit; } - *offsets = rec_get_offsets(clust_rec, clust_index, *offsets, true, + *offsets = rec_get_offsets(clust_rec, clust_index, *offsets, + clust_index->n_core_fields, ULINT_UNDEFINED, offset_heap); if (prebuilt->select_lock_type != LOCK_NONE) { @@ -3437,7 +3447,8 @@ Row_sel_get_clust_rec_for_mysql::operator()( ut_d(check_eq(clust_index, *offsets)); *offsets = rec_get_offsets( old_vers, clust_index, *offsets, - true, ULINT_UNDEFINED, offset_heap); + clust_index->n_core_fields, + ULINT_UNDEFINED, offset_heap); } } @@ -3866,7 +3877,7 @@ exhausted: /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ - *offsets = rec_get_offsets(rec, index, *offsets, true, + *offsets = rec_get_offsets(rec, index, *offsets, index->n_core_fields, ULINT_UNDEFINED, heap); if (!lock_clust_rec_cons_read_sees(rec, index, *offsets, @@ -4032,7 +4043,7 @@ row_sel_fill_vrow( ut_ad(!index->is_instant()); ut_ad(page_rec_is_leaf(rec)); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); *vrow = dtuple_create_with_vcol( @@ -4665,7 +4676,7 @@ wait_table_again: const rec_t* next_rec = page_rec_get_next_const(rec); offsets = rec_get_offsets(next_rec, index, offsets, - true, + index->n_core_fields, ULINT_UNDEFINED, &heap); err = sel_set_rec_lock(pcur, next_rec, index, offsets, @@ -4746,7 +4757,8 @@ rec_loop: we do not lock gaps. Supremum record is really a gap and therefore we do not set locks there. */ - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); err = sel_set_rec_lock(pcur, rec, index, offsets, @@ -4848,7 +4860,7 @@ wrong_offs: ut_ad(fil_page_index_page_check(btr_pcur_get_page(pcur))); ut_ad(btr_page_get_index_id(btr_pcur_get_page(pcur)) == index->id); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &heap); if (UNIV_UNLIKELY(srv_force_recovery > 0)) { @@ -5091,7 +5103,8 @@ no_gap_lock: Do a normal locking read. */ offsets = rec_get_offsets( - rec, index, offsets, true, + rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); goto locks_ok; case DB_DEADLOCK: @@ -5461,7 +5474,7 @@ use_covering_index: /* We used 'offsets' for the clust rec, recalculate them for 'rec' */ offsets = rec_get_offsets(rec, index, offsets, - true, + index->n_core_fields, ULINT_UNDEFINED, &heap); result_rec = rec; @@ -5920,7 +5933,7 @@ row_search_autoinc_read_column( rec_offs_init(offsets_); ut_ad(page_rec_is_leaf(rec)); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, col_no + 1, &heap); if (rec_offs_nth_sql_null(offsets, col_no)) { diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 0ce136c5906..d4e09431aae 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -120,7 +120,8 @@ row_undo_ins_remove_clust_rec( if (online && dict_index_is_online_ddl(index)) { mem_heap_t* heap = NULL; const rec_offs* offsets = rec_get_offsets( - rec, index, NULL, true, ULINT_UNDEFINED, &heap); + rec, index, NULL, index->n_core_fields, + ULINT_UNDEFINED, &heap); row_log_table_delete(rec, index, offsets, NULL); mem_heap_free(heap); } else { diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index e52ca5815f3..a7af11bacb9 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -189,8 +189,9 @@ static ulint row_trx_id_offset(const rec_t* rec, const dict_index_t* index) rec_offs_init(offsets_); mem_heap_t* heap = NULL; const ulint trx_id_pos = index->n_uniq ? index->n_uniq : 1; - rec_offs* offsets = rec_get_offsets(rec, index, offsets_, true, - trx_id_pos + 1, &heap); + rec_offs* offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, + trx_id_pos + 1, &heap); ut_ad(!heap); ulint len; trx_id_offset = rec_get_nth_field_offs( @@ -457,9 +458,9 @@ row_undo_mod_clust( } else { ut_ad(index->n_uniq <= MAX_REF_PARTS); rec_offs_init(offsets_); - offsets = rec_get_offsets( - rec, index, offsets_, true, trx_id_pos + 2, - &heap); + offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, + trx_id_pos + 2, &heap); ulint len; trx_id_offset = rec_get_nth_field_offs( offsets, trx_id_pos, &len); @@ -845,7 +846,8 @@ try_again: offsets_heap = NULL; offsets = rec_get_offsets( btr_cur_get_rec(btr_cur), - index, NULL, true, ULINT_UNDEFINED, &offsets_heap); + index, nullptr, index->n_core_fields, ULINT_UNDEFINED, + &offsets_heap); update = row_upd_build_sec_rec_difference_binary( btr_cur_get_rec(btr_cur), index, offsets, entry, heap); if (upd_get_n_fields(update) == 0) { diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 375de331255..6aaa8266316 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -187,7 +187,8 @@ row_undo_search_clust_to_pcur( rec = btr_pcur_get_rec(&node->pcur); - offsets = rec_get_offsets(rec, clust_index, offsets, true, + offsets = rec_get_offsets(rec, clust_index, offsets, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); found = row_get_rec_roll_ptr(rec, clust_index, offsets) diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index e8fdd7b249a..975e917a585 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -693,7 +693,8 @@ row_upd_build_difference_binary( n_diff = 0; if (!offsets) { - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, + index->n_core_fields, ULINT_UNDEFINED, &heap); } else { ut_ad(rec_offs_validate(rec, index, offsets)); @@ -1894,7 +1895,8 @@ row_upd_store_row( rec = btr_pcur_get_rec(node->pcur); - offsets = rec_get_offsets(rec, clust_index, offsets_, true, + offsets = rec_get_offsets(rec, clust_index, offsets_, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); if (dict_table_has_atomic_blobs(node->table)) { @@ -2133,7 +2135,7 @@ row_upd_sec_index_entry( && !wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { rec_offs* offsets = rec_get_offsets( - rec, index, NULL, true, + rec, index, NULL, index->n_core_fields, ULINT_UNDEFINED, &heap); err = wsrep_row_upd_check_foreign_constraints( @@ -2176,12 +2178,9 @@ row_upd_sec_index_entry( ut_ad(err == DB_SUCCESS); if (referenced) { - - rec_offs* offsets; - - offsets = rec_get_offsets( - rec, index, NULL, true, ULINT_UNDEFINED, - &heap); + rec_offs* offsets = rec_get_offsets( + rec, index, NULL, index->n_core_fields, + ULINT_UNDEFINED, &heap); /* NOTE that the following call loses the position of pcur ! */ @@ -2432,7 +2431,8 @@ row_upd_clust_rec_by_insert( we update the primary key. Delete-mark the old record in the clustered index and prepare to insert a new entry. */ rec = btr_cur_get_rec(btr_cur); - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, + index->n_core_fields, ULINT_UNDEFINED, &heap); ut_ad(page_rec_is_user_rec(rec)); @@ -2821,7 +2821,7 @@ row_upd_clust_step( } rec = btr_pcur_get_rec(pcur); - offsets = rec_get_offsets(rec, index, offsets_, true, + offsets = rec_get_offsets(rec, index, offsets_, index->n_core_fields, ULINT_UNDEFINED, &heap); if (!flags && !node->has_clust_rec_x_lock) { diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 7f410487b9a..f096149b0aa 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -116,7 +116,8 @@ row_vers_impl_x_locked_low( heap = mem_heap_create(1024); clust_offsets = rec_get_offsets(clust_rec, clust_index, clust_offsets_, - true, ULINT_UNDEFINED, &heap); + clust_index->n_core_fields, + ULINT_UNDEFINED, &heap); trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets); if (trx_id == 0) { @@ -239,7 +240,8 @@ not_locked: } clust_offsets = rec_get_offsets( - prev_version, clust_index, clust_offsets_, true, + prev_version, clust_index, clust_offsets_, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); vers_del = rec_get_deleted_flag(prev_version, comp); @@ -553,7 +555,8 @@ row_vers_build_cur_vrow_low( clust_offsets = rec_get_offsets(prev_version, clust_index, NULL, - true, ULINT_UNDEFINED, &heap); + clust_index->n_core_fields, + ULINT_UNDEFINED, &heap); ulint entry_len = dict_index_get_n_fields(index); @@ -694,7 +697,8 @@ row_vers_vc_matches_cluster( clust_offsets = rec_get_offsets(prev_version, clust_index, NULL, - true, ULINT_UNDEFINED, &heap); + clust_index->n_core_fields, + ULINT_UNDEFINED, &heap); ulint entry_len = dict_index_get_n_fields(index); @@ -821,7 +825,8 @@ row_vers_build_cur_vrow( index, roll_ptr, trx_id, v_heap, &cur_vrow, mtr); } - *clust_offsets = rec_get_offsets(rec, clust_index, NULL, true, + *clust_offsets = rec_get_offsets(rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); return(cur_vrow); } @@ -873,7 +878,8 @@ row_vers_old_has_index_entry( comp = page_rec_is_comp(rec); ut_ad(!dict_table_is_comp(index->table) == !comp); heap = mem_heap_create(1024); - clust_offsets = rec_get_offsets(rec, clust_index, NULL, true, + clust_offsets = rec_get_offsets(rec, clust_index, NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); if (dict_index_has_virtual(index)) { @@ -951,7 +957,8 @@ row_vers_old_has_index_entry( } } clust_offsets = rec_get_offsets(rec, clust_index, NULL, - true, + clust_index + ->n_core_fields, ULINT_UNDEFINED, &heap); } else { @@ -1026,7 +1033,8 @@ unsafe_to_purge: } clust_offsets = rec_get_offsets(prev_version, clust_index, - NULL, true, + NULL, + clust_index->n_core_fields, ULINT_UNDEFINED, &heap); if (dict_index_has_virtual(index)) { @@ -1167,7 +1175,7 @@ row_vers_build_for_consistent_read( *offsets = rec_get_offsets( prev_version, index, *offsets, - true, ULINT_UNDEFINED, offset_heap); + index->n_core_fields, ULINT_UNDEFINED, offset_heap); #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG ut_a(!rec_offs_any_null_extern(prev_version, *offsets)); @@ -1283,11 +1291,10 @@ committed_version_trx: semi-consistent read. */ version = rec; - *offsets = rec_get_offsets(version, - index, *offsets, - true, - ULINT_UNDEFINED, - offset_heap); + *offsets = rec_get_offsets( + version, index, *offsets, + index->n_core_fields, ULINT_UNDEFINED, + offset_heap); } buf = static_cast<byte*>( @@ -1330,7 +1337,8 @@ committed_version_trx: } version = prev_version; - *offsets = rec_get_offsets(version, index, *offsets, true, + *offsets = rec_get_offsets(version, index, *offsets, + index->n_core_fields, ULINT_UNDEFINED, offset_heap); #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG ut_a(!rec_offs_any_null_extern(version, *offsets)); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 3b6a63a3251..261e50285b7 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1598,7 +1598,7 @@ file_checked: to the data files and truncate or delete the log. Unless --export is specified, no further change to InnoDB files is needed. */ - ut_ad(!srv_force_recovery); + ut_ad(srv_force_recovery <= SRV_FORCE_IGNORE_CORRUPT); ut_ad(recv_no_log_write); err = fil_write_flushed_lsn(log_sys.get_lsn()); DBUG_ASSERT(!buf_pool.any_io_pending()); diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 22a0926a6de..d49fcb4f52d 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -651,7 +651,8 @@ fill_lock_data( ut_a(n_fields > 0); heap = NULL; - offsets = rec_get_offsets(rec, index, offsets, true, n_fields, &heap); + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, + n_fields, &heap); /* format and store the data */ diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 1df61ac5b56..714e527b259 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2472,7 +2472,8 @@ trx_undo_prev_version_build( rec_offs offsets_dbg[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_dbg); ut_a(!rec_offs_any_null_extern( - *old_vers, rec_get_offsets(*old_vers, index, offsets_dbg, true, + *old_vers, rec_get_offsets(*old_vers, index, offsets_dbg, + index->n_core_fields, ULINT_UNDEFINED, &heap))); #endif // defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 9011ca8f2e1..3064645f556 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc index fa04af6de13..1dd1cff6ece 100644 --- a/storage/innobase/ut/ut0ut.cc +++ b/storage/innobase/ut/ut0ut.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -637,7 +637,7 @@ const char * dbug_print_rec(const rec_t* rec, dict_index_t* index) rec_offs* offsets = offsets_; rec_offs_init(offsets_); mem_heap_t* tmp_heap = NULL; - offsets = rec_get_offsets(rec, index, offsets, true, + offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields, ULINT_UNDEFINED, &tmp_heap); rec_printer r(rec, offsets); strmake(dbug_print_buf, r.str().c_str(), sizeof(dbug_print_buf) - 1); |