diff --git a/CMakeLists.txt b/CMakeLists.txt index 29a47bf59d5..7d753c4e0e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,6 +274,16 @@ IF (WITH_MSAN) ENDIF() ENDIF() +# SANs, with their additional processing workload, should have a basic +# but debuggable optimization unless user specifies otherwise. +IF((WITH_ASAN OR WITH_UBSAN OR WITH_TSAN OR WITH_MSAN) + AND NOT CMAKE_C_FLAGS MATCHES "-O[0-9sgzf]" + AND NOT CMAKE_CXX_FLAGS MATCHES "-O[0-9sgzf]" + AND NOT CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE} MATCHES "-O[0-9sgzf]" + AND NOT CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} MATCHES "-O[0-9sgzf]") + MY_CHECK_AND_SET_COMPILER_FLAG("-Og") +ENDIF() + OPTION(WITH_GPROF "Enable profiling with gprof" OFF) IF (WITH_GPROF) MY_CHECK_AND_SET_COMPILER_FLAG("-pg -g -no-pie -fPIC") @@ -574,9 +584,6 @@ INSTALL_DOCUMENTATION(README.md CREDITS COPYING THIRDPARTY COMPONENT Readme) IF(UNIX) INSTALL_DOCUMENTATION(Docs/INSTALL-BINARY COMPONENT Readme) - IF(WITH_WSREP) - INSTALL_DOCUMENTATION(Docs/README-wsrep COMPONENT Readme) - ENDIF() ENDIF() INCLUDE(build_depends) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afceafb8172..fa60cd0886e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,14 +15,16 @@ MariaDB Server has a vibrant community contributing in a wide range of areas. Th - Contribute towards [documenting MariaDB Server](https://mariadb.com/docs/general-resources/about/readme/contributing-documentation) and its ecosystem by adding new content or improving existing content. - [Translate](https://mariadb.com/docs/general-resources/about/readme/contributing-documentation) existing documentation. -### Help debug and develop MariaDB +### Help develop MariaDB ----- -- [Report bugs](https://jira.mariadb.org/) -- Test development versions -- Write code to fix bugs or develop new features (see [Getting Started for Developers](https://mariadb.org/getting-started-for-developers)).See also [list of beginner friendly tasks](https://jira.mariadb.org/browse/MDEV-15736?jql=resolution%20%3D%20Unresolved%20AND%20labels%20%3D%20beginner-friendly%20ORDER%20BY%20updated%20DESC) -- Help with code quality control -- Participate in packaging for different Linux distributions -- Coding standards for the main source code can be found in [CODING_STANDARDS.md](CODING_STANDARDS.md). +- Fix bugs or develop new features +- Review code contributions +- Test bug fixes and features +- Participate in packaging for different distributions + +Check the [list of beginner friendly tasks](https://jira.mariadb.org/issues/?jql=status%3DConfirmed%20AND%20labels%3Dbeginner-friendly%20ORDER%20BY%20updated%20DESC). Or talk to the [MariaDB developers](#engage-online-with-other-community-members). + +See also [Getting Started for Developers](https://mariadb.org/getting-started-for-developers). Coding standards for the main source code can be found in [CODING_STANDARDS.md](CODING_STANDARDS.md). ### Sponsor or donate --- @@ -34,7 +36,7 @@ You’re very welcome to support MariaDB Server as an individual, or talk your c - [Events and Conferences page](https://mariadb.org/events/) - [mariadb.meetup.com](http://mariadb.meetup.com/) -### Live QA for beginner contributors +### Live Q&A for beginner contributors ---- MariaDB has a dedicated time each week when we answer new contributor questions live on Zulip. From 8:00 to 10:00 UTC on Mondays, and 10:00 to 12:00 UTC on Thursdays, anyone can ask any questions they’d like, @@ -43,5 +45,5 @@ New contributors can ask questions any time, but we will provide immediate feedb ### Additional resources ---- - - [MariaDB Foundation ](https://mariadb.org/) + - [MariaDB Foundation](https://mariadb.org/) - [MariaDB Documentation](https://mariadb.com/docs/) diff --git a/Docs/README-wsrep b/Docs/README-wsrep deleted file mode 100644 index 2e3bf52219d..00000000000 --- a/Docs/README-wsrep +++ /dev/null @@ -1,485 +0,0 @@ -Codership Oy -http://www.codership.com - - -DISCLAIMER - -THIS SOFTWARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -IN NO EVENT SHALL CODERSHIP OY BE HELD LIABLE TO ANY PARTY FOR ANY DAMAGES -RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE. - -Trademark Information. - -MySQL is a trademark or registered trademark of Oracle and/or its affiliates. -Other trademarks are the property of their respective owners. - -Licensing Information. - -Please see file COPYING that came with this distribution - -Source code can be found at -wsrep API: https://launchpad.net/wsrep -MySQL patch: https://launchpad.net/codership-mysql - - -ABOUT THIS DOCUMENT - -This document covers installation and configuration issues specific to this -wsrep-patched MySQL distribution by Codership. It does not cover the use or -administration of MySQL server per se. The reader is assumed to know how to -install, configure, administer and use standard MySQL server version 5.1.xx. - - - MYSQL-5.5.x/wsrep-23.x - -CONTENTS: -========= -1. WHAT IS WSREP PATCH FOR MYSQL -2. INSTALLATION -3. FIRST TIME SETUP - 3.1 CONFIGURATION FILES - 3.2 DATABASE PRIVILEGES - 3.3 CHECK AND CORRECT FIREWALL SETTINGS - 3.4 SELINUX - 3.5 APPARMOR - 3.6 CONNECT TO CLUSTER -4. UPGRADING FROM MySQL 5.1.x -5. CONFIGURATION OPTIONS - 5.1 MANDATORY MYSQL OPTIONS - 5.2 WSREP OPTIONS -6. ONLINE SCHEMA UPGRADE - 6.1 TOTAL ORDER ISOLATION (TOI) - 6.2 ROLLING SCHEMA UPGRADE (RSU) -7. LIMITATIONS - - -1. WHAT IS WSREP PATCH FOR MYSQL/INNODB - -Wsrep API developed by Codership Oy is a modern generic (database-agnostic) -replication API for transactional databases with a goal to make database -replication/logging subsystem completely modular and pluggable. It is developed -with flexibility and completeness in mind to satisfy a broad range of modern -replication scenarios. It is equally suitable for synchronous and asynchronous, -master-slave and multi-master replication. - -wsrep stands for Write Set REPlication. - -Wsrep patch for MySQL/InnoDB allows MySQL server to load and use various wsrep -API implementations ("wsrep providers") with different qualities of service. -Without wsrep provider MySQL-wsrep server will function like a regular -standalone server. - - -2. INSTALLATION - -In the examples below mysql authentication options are omitted for brevity. - -2.1 Download and install mysql-wsrep package. - -Download binary package for your Linux distribution from -https://launchpad.net/codership-mysql/ - -2.1.1 On Debian and Debian-derived distributions. - -Upgrade from mysql-server-5.0 to mysql-wsrep is not supported yet, please -upgrade to mysql-server-5.1 first. - -If you're installing over an existing mysql installation, mysql-server-wsrep -will conflict with the mysql-server-5.1 package, so remove it first: - -$ sudo apt-get remove mysql-server-5.1 mysql-server-core-5.1 - -mysql-server-wsrep requires psmisc and mysql-client-5.1.47 (or later). -MySQL 5.1 packages can be found from backports repositories. -For further information about configuring and using Debian or Ubuntu -backports, see: - -* http://backports.debian.org - -* https://help.ubuntu.com/community/UbuntuBackports - -For example, installation of required packages on Debian Lenny: - -$ sudo apt-get install psmisc -$ sudo apt-get -t lenny-backports install mysql-client-5.1 - -Now you should be able to install the mysql-wsrep package: - -$ sudo dpkg -i - -2.1.2 On CentOS and similar RPM-based distributions. - -If you're migrating from existing MySQL installation, there are two variants: - - a) If you're already using official MySQL-server-community 5.1.x RPM from - Oracle: - - # rpm -e mysql-server - - b) If you're upgrading from the stock mysql-5.0.77 on CentOS: - - 1) Make sure that the following packages are not installed: - # rpm --nodeps --allmatches -e mysql-server mysql-test mysql-bench - - 2) Install *official* MySQL-shared-compat-5.1.x from - http://dev.mysql.com/downloads/mysql/5.1.html - -Actual installation: - - # rpm -Uvh - - If this fails due to unsatisfied dependencies, install missing packages - (e.g. yum install perl-DBI) and retry. - -Additional packages to consider (if not yet installed): - * galera (multi-master replication provider, https://launchpad.net/galera) - * MySQL-client-community (for connecting to server and mysqldump-based SST) - * rsync (for rsync-based SST) - * mariabackup and nc (for mariabackup-based SST) - -2.2 Upgrade system tables. - -If you're upgrading a previous MySQL installation, it might be advisable to -upgrade system tables. To do that start mysqld and run mysql_upgrade command. -Consult MySQL documentation in case of errors. Normally they are not critical -and can be ignored unless specific functionality is needed. - - -3. FIRST TIME SETUP - -Unless you're upgrading an already installed mysql-wsrep package, you will need -to set up a few things to prepare the server for operation. - -3.1 CONFIGURATION FILES - -* Make sure system-wide my.cnf does not bind mysqld to 127.0.0.1. That is, if - you have the following line in [mysqld] section, comment it out: - - #bind-address = 127.0.0.1 - -* Make sure system-wide my.cnf contains "!includedir /etc/mysql/conf.d/" line. - -* Edit /etc/mysql/conf.d/wsrep.cnf and set wsrep_provider option by specifying - a path to the provider library. If you don't have a provider, leave it as it is. - -* When a new node joins the cluster it'll have to receive a state snapshot from - one of the peers. This requires a privileged MySQL account with access from - the rest of the cluster. Edit /etc/mysql/conf.d/wsrep.cnf and set mysql - login/password pair for SST, for example: - - wsrep_sst_auth=wsrep_sst:wspass - -* See CONFIGURATION section below about other configuration parameters that you - might want to change at this point. - -3.2 DATABASE PRIVILEGES - -Restart MySQL server and connect to it as root to grant privileges to SST -account (empty users confuse MySQL authentication matching rules, we need to -delete them too): - -$ mysql -e "SET wsrep_on=OFF; DELETE FROM mysql.user WHERE user='';" -$ mysql -e "SET wsrep_on=OFF; GRANT ALL ON *.* TO wsrep_sst@'%' IDENTIFIED BY 'wspass'"; - -3.3 CHECK AND CORRECT FIREWALL SETTINGS. - -MySQL-wsrep server needs to be accessible from other cluster members through -its client listening socket and through wsrep provider socket. See your -distribution and wsrep provider documentation for details. For example on -CentOS you might need to do something along these lines: - -# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 3306 -j ACCEPT -# iptables --insert RH-Firewall-1-INPUT 1 --proto tcp --source /24 --destination /32 --dport 4567 -j ACCEPT - -If there is a NAT firewall between the nodes, it must be configured to allow -direct connections between the nodes (e.g. via port forwarding). - -3.4 SELINUX - -If you have SELinux enabled, it may block mysqld from doing required operations. -You'll need to either disable it or configure to allow mysqld to run external -programs and open listen sockets at unprivileged ports (i.e. things that -an unprivileged user can do). See SELinux documentation about it. - -To quickly disable SELinux: -1) run 'setenforce 0' as root. -2) set 'SELINUX=permissive' in /etc/selinux/config - -3.5 APPARMOR - -AppArmor automatically comes with Ubuntu and may also prevent mysqld to from -opening additional ports or run scripts. See AppArmor documentation about its -configuration. To disable AppArmor for mysqld: - -$ cd /etc/apparmor.d/disable/ -$ sudo ln -s /etc/apparmor.d/usr.sbin.mysqld -$ sudo service apparmor restart - - -3.6 CONNECT TO CLUSTER - -Now you're ready to connect to cluster by setting wsrep_cluster_address variable -and monitor status of wsrep provider: - -mysql> SET GLOBAL wsrep_cluster_address=''; -mysql> SHOW STATUS LIKE 'wsrep%'; - - -4 UPGRADING FROM MySQL 5.1.x - -!!! THESE INSTRUCTIONS ARE PRELIMINARY AND INCOMPLETE !!! - -1) BEFORE UPGRADE (while running 5.1.x): - - comment out 'wsrep_provider' setting from configuration files - (my.cnf and/or wsrep.cnf) - - If performing a rolling upgrade on a running cluster, set - wsrep_sst_method=mysqldump. - You might also need to configure wsrep_sst_receive_address and - wsrep_sst_auth appropriately. mysqldump is the only way to transfer data - from 5.1.x to 5.5.x reliably. - - remove innodb_plugin settings from configuration files. - -2) Perform upgrade as usual: - http://dev.mysql.com/doc/refman/5.5/en/upgrading-from-previous-series.html - Don't forget to run 'mysql_upgrade' command. - -3) AFTER UPGRADING individual node: - - uncomment 'wsrep_provider' line in configuration file. - - restart the server and join the cluster. - -4) AFTER UPGRADING the whole cluster: - - revert to usual wsrep SST settings if not 'mysqldump'. - - -5. CONFIGURATION OPTIONS - -5.1 MANDATORY MYSQL OPTIONS - -binlog_format=ROW - This option is required to use row-level replication as opposed to - statement-level. For performance and consistency considerations don't change - that. As a side effect, binlog, if turned on, can be ROW only. In future this - option won't have special meaning. - -innodb_autoinc_lock_mode=2 - This is a required parameter. Without it INSERTs into tables with - AUTO_INCREMENT column may fail. - autoinc lock modes 0 and 1 can cause unresolved deadlock, and make - the system unresponsive. - -5.2 WSREP OPTIONS - -All options are optional except for wsrep_provider, wsrep_cluster_address, and -wsrep_sst_auth. - -wsrep_provider=none - A full path to the library that implements WSREP interface. If none is - specified, the server behaves like a regular mysqld. - -wsrep_provider_options= - Provider-specific option string. Check wsrep provider documentation or - http://www.codership.com/wiki - -wsrep_cluster_address= - Provider-specific cluster address string. This is used to connect a node to - the desired cluster. This option can be given either on mysqld startup or set - during runtime. See wsrep provider documentation for possible values. - -wsrep_cluster_name="my_wsrep_cluster" - Logical cluster name, must be the same for all nodes of the cluster. - -wsrep_node_address= - An option to explicitly specify the network address of the node in the form -
[:port] if autoguessing for some reason does not produce desirable - results (multiple network interfaces, NAT, etc.) - If not explicitly overridden by wsrep_sst_receive_address, the
part - will be used to listen for SST (see below). And the whole
[:port] - will be passed to the wsrep provider to be used as a base address in its - communications. - -wsrep_node_name= - Human readable node name (for easier log reading only). Defaults to hostname. - -wsrep_slave_threads=1 - The number of threads dedicated to the processing of writesets from other nodes. - For best performance should be few per CPU core. - -wsrep_dbug_option - Options for the built-in DBUG library (independent from what MySQL uses). - Empty by default. Not currently in use. - -wsrep_debug=0 - Enable debug-level logging. - -wsrep_convert_LOCK_to_trx=0 - Implicitly convert locking sessions into transactions inside mysqld. By - itself it does not mean support for locking sessions, but it prevents the - database from going into logically inconsistent state. Note however, that - loading large database dump with LOCK statements might result in abnormally - large transactions and cause an out-of-memory condition - -wsrep_retry_autocommit=1 - Retry autocommit queries and single statement transactions should they fail - certification test. This is analogous to rescheduling an autocommit query - should it go into a deadlock with other transactions in the database lock - manager. - -wsrep_auto_increment_control=1 - Automatically adjust auto_increment_increment and auto_increment_offset - variables based on the number of nodes in the cluster. Significantly reduces - certification conflict rate for INSERTS. - -wsrep_drupal_282555_workaround=1 - MySQL seems to have an obscure bug when INSERT into table with - AUTO_INCREMENT column with NULL value for that column can fail with a - duplicate key error. When this option is on, it retries such INSERTs. - Required for stable Drupal operation. Documented at: - http://bugs.mysql.com/bug.php?id=41984 - http://drupal.org/node/282555 - -wsrep_causal_reads=0 - Enforce strict READ COMMITTED semantics on reads and transactions. May - result in additional latencies. It is a session variable. - -wsrep_OSU_method=TOI - Online Schema Upgrade (OSU) can be performed with two alternative methods: - Total Order Isolation (TOI) runs DDL statement in all cluster nodes in - same total order sequence locking the affected table for the duration of the - operation. This may result in the whole cluster being blocked for the - duration of the operation. - Rolling Schema Upgrade (RSU) executes the DDL statement only locally, thus - blocking only one cluster node. During the DDL processing, the node - is not replicating and may be unable to process replication events (due to - table lock). Once DDL operation is complete, the node will catch up and sync - with the cluster to become fully operational again. The DDL statement or - its effects are not replicated, so it is the user's responsibility to manually - perform this operation on each of the nodes. - -wsrep_forced_binlog_format=none - Force every transaction to use given binlog format. When this variable is - set to something else than NONE, all transactions will use the given forced - format, regardless of what the client session has specified in binlog_format. - Valid choices for wsrep_forced_binlog_format are: ROW, STATEMENT, MIXED and - special value NONE, meaning that there is no forced binlog format in effect. - This variable was introduced to support STATEMENT format replication during - rolling schema upgrade processing. However, in most cases ROW replication - is valid for asymmetric schema replication. - -State snapshot transfer options. - -When a new node joins the cluster it has to synchronize its initial state with -the other cluster members by transferring state snapshot from one of them. -The options below govern how this happens and should be set up before attempting -to join or start a cluster. - -wsrep_sst_method=rsync - What method to use to copy database state to a newly joined node. Supported - methods: - - mysqldump: slow (except for small datasets) but allows for upgrade - between major MySQL versions or InnoDB features. - - rsync: much faster on large datasets (default). - - rsync_wan: same as rsync but with deltaxfer to minimize network traffic. - - mariabackup: very fast and practically non-blocking SST method based on - mariabackup tool (enhanced version of Percona's xtrabackup). - - (for mariabackup to work the following settings must be present in my.cnf - on all nodes: - [mysqld] - wsrep_sst_auth=root: - datadir= - [client] - socket= - ) - -wsrep_sst_receive_address= - Address (hostname:port) at which this node wants to receive state snapshot. - Defaults to mysqld bind address, and if that is not specified (0.0.0.0) - - to the first IP of eth0 + mysqld bind port. - NOTE: check that your firewall allows connections to this address from other - cluster nodes. - -wsrep_sst_auth= - Authentication information needed for state transfer. Depends on the state - transfer method. For mysqldump-based SST it is - : - and should be the same on all nodes - it is used to authenticate with both - state snapshot receiver and state snapshot donor. - -wsrep_sst_donor= - A name of the node which should serve as state snapshot donor. This allows - controlling which node will serve the state snapshot request. By default the - most suitable node is chosen by the wsrep provider. This is the same as given in - wsrep_node_name. - - -6. ONLINE SCHEMA UPGRADE - - Schema upgrades mean any data definition statements (DDL statements) run - for the database. They change the database structure and are non- - transactional. - - Release 22.3 brings a new method for performing schema upgrades. A user can - now choose whether to use the traditional total order isolation or new - rolling schema upgrade method. The OSU method choice is done by global - parameter: 'wsrep_OSU_method'. - -6.1 Total Order Isolation (TOI) - - With earlier releases, DDL processing happened always by Total Order - Isolation (TOI) method. With TOI, the DDL was scheduled to be processed in - same transaction sequencing 'slot' in each cluster node. - The processing is secured by locking the affected table from any other use. - With TOI method, the whole cluster has part of the database locked for the - duration of the DDL processing. - -6.2 Rolling Schema Upgrade (RSU) - - Rolling schema upgrade is a new DDL processing method, where DDL will be - processed locally for the node. The node is disconnected of the replication - for the duration of the DDL processing, so that there is only DDL statement - processing in the node and it does not block the rest of the cluster. When - the DDL processing is complete, the node applies delayed replication events - and synchronizes back with the cluster. - The DDL can then be executed cluster-wide by running the same DDL statement - for each node in turn. When this rolling schema upgrade proceeds, part of - the cluster will have old schema structure and part of the cluster will have - new schema structure. - - -7. LIMITATIONS - -1) Currently replication works only with InnoDB storage engine. Any writes to - tables of other types, including system (mysql.*) tables are not replicated. - However, DDL statements are replicated in statement level, and changes - to mysql.* tables will get replicated that way. - So, you can safely issue: CREATE USER..., - but issuing: INSERT INTO mysql.user..., will not be replicated. - -2) DELETE operation is unsupported on tables without primary key. Also rows in - tables without primary key may appear in different order on different nodes. - As a result SELECT...LIMIT... may return slightly different sets. - -3) Unsupported queries: - * LOCK/UNLOCK TABLES cannot be supported in multi-master setups. - * lock functions (GET_LOCK(), RELEASE_LOCK()... ) - -4) Query log cannot be directed to a table. If you enable query logging, - you must forward the log to a file: - log_output = FILE - Use general_log and general_log_file to choose query logging and the - log file name - -5) Maximum allowed transaction size is defined by wsrep_max_ws_rows and - wsrep_max_ws_size. Anything bigger (e.g. huge LOAD DATA) will be rejected. - -6) Due to cluster level optimistic concurrency control, transaction issuing - COMMIT may still be aborted at that stage. There can be two transactions. - writing to same rows and committing in separate cluster nodes, and only one - of them can successfully commit. The failing one will be aborted. - For cluster level aborts, MySQL/galera cluster gives back deadlock error. - code (Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)). - -7) XA transactions can not be supported due to possible rollback on commit. - diff --git a/client/mysql.cc b/client/mysql.cc index 3158d270ae7..283578f3c8c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1475,13 +1475,25 @@ int main(int argc,char *argv[]) if (verbose) tee_fprintf(stdout, "Reading history-file %s\n",histfile); read_history(histfile); - if (!(histfile_tmp= (char*) my_malloc(PSI_NOT_INSTRUMENTED, - strlen(histfile) + 5, MYF(MY_WME)))) { - fprintf(stderr, "Couldn't allocate memory for temp histfile!\n"); - exit(1); + /* Extra space for the suffix appended to histfile: + "." - separator (sizeof = 2, includes NUL) + + PID - up to 20 digits (ULONG_MAX = 18446744073709551615) + + ".TMP"- extension (sizeof = 5, includes NUL, doubles + as the string NUL terminator) + sizeof(".") and sizeof(".TMP") each carry a NUL, so the sum + over-allocates by one byte, which is intentional. */ + size_t hlen= strlen(histfile) + sizeof(".") + 20 + sizeof(".TMP"); + if (!(histfile_tmp= (char*) my_malloc(PSI_NOT_INSTRUMENTED, hlen, MYF(MY_WME)))) + { + fprintf(stderr, "Couldn't allocate memory for temp histfile!\n"); + exit(1); + } + /* Include PID in name to avoid rename collision when concurrent sessions exit. */ + /* pid_t is signed but getpid() always returns a non-negative value (POSIX). */ + snprintf(histfile_tmp, hlen, "%s.%lu.TMP", histfile, + (unsigned long) getpid()); } - sprintf(histfile_tmp, "%s.TMP", histfile); } } @@ -3656,7 +3668,6 @@ static int com_go(String *buffer, char *) timer= microsecond_interval_timer(); executing_query= 1; error= mysql_real_query_for_lazy(buffer->ptr(),buffer->length()); - report_progress_end(); #ifdef HAVE_READLINE if (status.add_to_history) @@ -3694,6 +3705,7 @@ static int com_go(String *buffer, char *) goto end; } + report_progress_end(); if (verbose >= 3 || !opt_silent) end_timer(timer, time_buff); else @@ -4001,6 +4013,16 @@ print_as_hex(FILE *output_file, const char *str, size_t len, size_t total_bytes_ tee_putc((int)' ', output_file); } +static inline MYSQL_ROW fetch_row(MYSQL_RES *result) +{ + MYSQL_ROW row = mysql_fetch_row(result); +#ifndef EMBEDDED_LIBRARY + if (last_progress_report_length) { + report_progress_end(); + } +#endif + return row; +} static void print_table_data(MYSQL_RES *result) @@ -4057,7 +4079,7 @@ print_table_data(MYSQL_RES *result) tee_puts((char*) separator.ptr(), PAGER); } - while ((cur= mysql_fetch_row(result))) + while ((cur = fetch_row(result))) { if (interrupted_query) break; @@ -4229,7 +4251,7 @@ static void print_table_data_html(MYSQL_RES *result) } (void) tee_fputs("", PAGER); } - while ((cur = mysql_fetch_row(result))) + while ((cur = fetch_row(result))) { if (interrupted_query) break; @@ -4265,7 +4287,7 @@ print_table_data_xml(MYSQL_RES *result) PAGER); fields = mysql_fetch_fields(result); - while ((cur = mysql_fetch_row(result))) + while ((cur = fetch_row(result))) { if (interrupted_query) break; @@ -4309,7 +4331,7 @@ print_table_data_vertically(MYSQL_RES *result) } mysql_field_seek(result,0); - for (uint row_count=1; (cur= mysql_fetch_row(result)); row_count++) + for (uint row_count=1; (cur = fetch_row(result)); row_count++) { if (interrupted_query) break; @@ -4510,7 +4532,7 @@ print_tab_data(MYSQL_RES *result) } (void) tee_fputs("\n", PAGER); } - while ((cur = mysql_fetch_row(result))) + while ((cur = fetch_row(result))) { lengths=mysql_fetch_lengths(result); field= mysql_fetch_fields(result); diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index b901cad2c4c..9e23cb7436a 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -1073,7 +1073,7 @@ static void __attribute__((noinline)) print_result() continue; } if (status && changed) - printf("%-50s %s", row[0], row[3]); + printf("%-50s %s\n", row[0], row[3]); else if (!status && changed) { /* @@ -1086,16 +1086,16 @@ static void __attribute__((noinline)) print_result() */ if (!strcmp(row[2],"error") && strstr(row[3],"REPAIR ")) { - printf("%-50s %s", row[0], "Needs upgrade with REPAIR"); + printf("%-50s %s\n", row[0], "Needs upgrade with REPAIR"); array4repair= strstr(row[3], "VIEW") ? &views4repair : &tables4repair; } else if (!strcmp(row[2],"error") && strstr(row[3],"ALTER TABLE")) { - printf("%-50s %s", row[0], "Needs upgrade with ALTER TABLE FORCE"); + printf("%-50s %s\n", row[0], "Needs upgrade with ALTER TABLE FORCE"); array4repair= &tables4rebuild; } else - printf("%s\n%-9s: %s", row[0], row[2], row[3]); + printf("%s\n%-9s: %s\n", row[0], row[2], row[3]); if (strcmp(row[2],"note")) { found_error=1; @@ -1104,9 +1104,8 @@ static void __attribute__((noinline)) print_result() } } else - printf("%-9s: %s", row[2], row[3]); + printf("%-9s: %s\n", row[2], row[3]); strmov(prev, row[0]); - putchar('\n'); } /* add the last table to be repaired to the list */ if (found_error && opt_auto_repair && what_to_do != DO_REPAIR) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index 16b3b9af733..831287d2bf3 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -221,5 +221,3 @@ include(${_SCRIPT_DIR}/WindowsCache.cmake) # this is out of place, not really a system check set(FN_NO_CASE_SENSE 1) set(USE_SYMDIR 1) -set(HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT 1) - diff --git a/config.h.cmake b/config.h.cmake index 11ec0590bcb..b378b464c9b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -446,11 +446,6 @@ /* This should mean case insensitive file system */ #cmakedefine FN_NO_CASE_SENSE 1 -/* Whether an anonymous private mapping is unaccessible after -madvise(MADV_DONTNEED) or madvise(MADV_FREE) or similar has been invoked; -this is the case with Microsoft Windows VirtualFree(MEM_DECOMMIT) */ -#cmakedefine HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT 1 - #cmakedefine HAVE_CHARSET_armscii8 1 #cmakedefine HAVE_CHARSET_ascii 1 #cmakedefine HAVE_CHARSET_big5 1 diff --git a/debian/additions/mariadb.conf.d/50-server.cnf b/debian/additions/mariadb.conf.d/50-server.cnf index db4625ba550..e23b02d08cd 100644 --- a/debian/additions/mariadb.conf.d/50-server.cnf +++ b/debian/additions/mariadb.conf.d/50-server.cnf @@ -59,8 +59,10 @@ bind-address = 127.0.0.1 # journald. # Enable this if you want to have error logging into a separate file #log_error = /var/log/mysql/error.log + # Enable the slow query log to see queries with especially long duration #log_slow_query_file = /var/log/mysql/mariadb-slow.log +#slow_query_log = 1 #log_slow_query_time = 10 #log_slow_verbosity = query_plan,explain #log-queries-not-using-indexes diff --git a/debian/changelog b/debian/changelog index 254fc91e4aa..e327c438951 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,4 +2,4 @@ mariadb (1:12.3.0) unstable; urgency=medium * Initial Release - -- Sergei Golubchik Mon Aug 4 21:26:56 CEST 2025 + -- Sergei Golubchik Mon, 4 Aug 2025 21:26:56 +0200 diff --git a/debian/control b/debian/control index eb73631d68c..79163bd8eb7 100644 --- a/debian/control +++ b/debian/control @@ -19,7 +19,6 @@ Build-Depends: libboost-dev, libboost-filesystem-dev [amd64 arm64], libboost-regex-dev [amd64 arm64], - libboost-system-dev [amd64 arm64], libboost-thread-dev [amd64 arm64], libbz2-dev, libcrack2-dev (>= 2.9.0), diff --git a/debian/mariadb-plugin-mroonga.postinst b/debian/mariadb-plugin-mroonga.postinst index 5c3b293d476..22cae86249f 100644 --- a/debian/mariadb-plugin-mroonga.postinst +++ b/debian/mariadb-plugin-mroonga.postinst @@ -3,8 +3,8 @@ set -e # Install Mroonga -mariadb --defaults-file=/etc/mysql/debian.cnf < /usr/share/mysql/mroonga/install.sql || true +mariadb --defaults-file=/etc/mysql/debian.cnf < /usr/share/mariadb/mroonga/install.sql || true # Always exit with success instead of leaving dpkg in a broken state -#DEBHELPER# +#DEBHELPER# \ No newline at end of file diff --git a/extra/mariabackup/ds_local.cc b/extra/mariabackup/ds_local.cc index bd2b6d02ecd..cc02539d97d 100644 --- a/extra/mariabackup/ds_local.cc +++ b/extra/mariabackup/ds_local.cc @@ -136,6 +136,7 @@ local_open(ds_ctxt_t *ctxt, const char *path, local_file = (ds_local_file_t *) (file + 1); local_file->fd = fd; + posix_fadvise(local_file->fd, 0, 0, POSIX_FADV_DONTNEED); local_file->init_ibd_done = 0; local_file->is_ibd = (path_len > 5) && !strcmp(fullpath + path_len - 5, ".ibd"); local_file->compressed = 0; @@ -166,9 +167,7 @@ static int write_compressed(File fd, uchar *data, size_t len, size_t pagesize) size_t n_bytes = MY_MIN(pagesize, len - written); size_t datasize= trim_binary_zeros(ptr,n_bytes); if (datasize > 0) { - if (!my_write(fd, ptr, datasize, MYF(MY_WME | MY_NABP))) - posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); - else + if (my_write(fd, ptr, datasize, MYF(MY_WME | MY_NABP))) return 1; } if (datasize < n_bytes) { @@ -242,11 +241,10 @@ local_write(ds_file_t *file, const uchar *buf, size_t len) return write_compressed(fd, b, len, local_file->pagesize); } - if (!my_write(fd, b , len, MYF(MY_WME | MY_NABP))) { - posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); - return 0; + if (my_write(fd, b , len, MYF(MY_WME | MY_NABP))) { + return 1; } - return 1; + return 0; } static diff --git a/extra/mariabackup/ds_stdout.cc b/extra/mariabackup/ds_stdout.cc index 3fc0873b6ca..a05740c37b7 100644 --- a/extra/mariabackup/ds_stdout.cc +++ b/extra/mariabackup/ds_stdout.cc @@ -84,6 +84,7 @@ stdout_open(ds_ctxt_t *ctxt __attribute__((unused)), #endif stdout_file->fd = my_fileno(stdout); + posix_fadvise(stdout_file->fd, 0, 0, POSIX_FADV_DONTNEED); file->path = (char *) stdout_file + sizeof(ds_stdout_file_t); memcpy(file->path, fullpath, pathlen); @@ -99,12 +100,11 @@ stdout_write(ds_file_t *file, const uchar *buf, size_t len) { File fd = ((ds_stdout_file_t *) file->ptr)->fd; - if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { - posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); - return 0; + if (my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { + return 1; } - return 1; + return 0; } static diff --git a/extra/mariabackup/ds_tmpfile.cc b/extra/mariabackup/ds_tmpfile.cc index 6bafee25971..2067b6d7d96 100644 --- a/extra/mariabackup/ds_tmpfile.cc +++ b/extra/mariabackup/ds_tmpfile.cc @@ -115,6 +115,7 @@ tmpfile_open(ds_ctxt_t *ctxt, const char *path, tmp_file->orig_path = (char *) tmp_file + sizeof(ds_tmp_file_t); tmp_file->fd = fd; + posix_fadvise(tmp_file->fd, 0, 0, POSIX_FADV_DONTNEED); memcpy(tmp_file->orig_path, path, path_len); /* Store the real temporary file name in file->path */ @@ -138,12 +139,11 @@ tmpfile_write(ds_file_t *file, const uchar *buf, size_t len) { File fd = ((ds_tmp_file_t *) file->ptr)->fd; - if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { - posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); - return 0; + if (my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { + return 1; } - return 1; + return 0; } static int diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 68d5923b3ae..26ec7a2fa26 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -2680,7 +2680,7 @@ static void log_hdr_init() log_sys.format == log_t::FORMAT_ENC_11 ? log_t::FORMAT_ENC_11 : log_t::FORMAT_10_8); mach_write_to_8(LOG_HEADER_START_LSN + log_hdr_buf, - log_sys.next_checkpoint_lsn); + log_sys.last_checkpoint_lsn); snprintf(reinterpret_cast(LOG_HEADER_CREATOR + log_hdr_buf), 16, "Backup %u.%u.%u", MYSQL_VERSION_ID / 10000, MYSQL_VERSION_ID / 100 % 100, @@ -2688,7 +2688,7 @@ static void log_hdr_init() if (log_sys.is_encrypted()) log_crypt_write_header(log_hdr_buf + LOG_HEADER_CREATOR_END); mach_write_to_4(508 + log_hdr_buf, my_crc32c(0, log_hdr_buf, 508)); - mach_write_to_8(log_hdr_buf + 0x1000, log_sys.next_checkpoint_lsn); + mach_write_to_8(log_hdr_buf + 0x1000, log_sys.last_checkpoint_lsn); mach_write_to_8(log_hdr_buf + 0x1008, recv_sys.lsn); mach_write_to_4(log_hdr_buf + 0x103c, my_crc32c(0, log_hdr_buf + 0x1000, 60)); @@ -2720,9 +2720,14 @@ static bool innodb_init() } ut_ad(srv_force_recovery <= SRV_FORCE_IGNORE_CORRUPT); + mysql_mutex_lock(&recv_sys.mutex); ut_ad(recv_no_log_write); - buf_flush_sync(); + if (recv_sys.recovery_on) + recv_sys.apply(true); + mysql_mutex_unlock(&recv_sys.mutex); recv_sys.debug_free(); + + buf_flush_sync_batch(0, false); ut_ad(!os_aio_pending_reads()); ut_d(mysql_mutex_lock(&buf_pool.flush_list_mutex)); ut_ad(!buf_pool.get_oldest_modification(0)); @@ -2757,7 +2762,7 @@ static bool innodb_init() return true; } - recv_sys.lsn= log_sys.next_checkpoint_lsn= + recv_sys.lsn= log_sys.last_checkpoint_lsn= log_get_lsn() - SIZE_OF_FILE_CHECKPOINT; log_sys.set_latest_format(false); // not encrypted log_hdr_init(); @@ -3664,7 +3669,7 @@ static bool backup_wait_timeout(lsn_t lsn, lsn_t last_lsn) return true; msg("Was only able to copy log from " LSN_PF " to " LSN_PF ", not " LSN_PF "; try increasing innodb_log_file_size", - log_sys.next_checkpoint_lsn, last_lsn, lsn); + log_sys.last_checkpoint_lsn.load(), last_lsn, lsn); return false; } @@ -4852,11 +4857,14 @@ static ulong xb_set_max_open_files(rlim_t max_file_limit) goto end; } - rlimit.rlim_cur = rlimit.rlim_max = max_file_limit; + rlimit.rlim_cur = max_file_limit; if (setrlimit(RLIMIT_NOFILE, &rlimit)) { /* Use original value */ max_file_limit = static_cast(old_cur); + + msg( "setrlimit failed %d %s limit S: %" PRIu64 " H: %" PRIu64, + errno, strerror(errno), rlimit.rlim_cur, rlimit.rlim_max); } else { rlimit.rlim_cur = 0; /* Safety if next call fails */ @@ -4919,9 +4927,9 @@ static bool backup_wait_for_commit_lsn() /* read the latest checkpoint lsn */ if (recv_sys.find_checkpoint() == DB_SUCCESS && log_sys.is_latest()) { - if (log_sys.next_checkpoint_lsn > lsn) - lsn= log_sys.next_checkpoint_lsn; - metadata_to_lsn= log_sys.next_checkpoint_lsn; + metadata_to_lsn= log_sys.last_checkpoint_lsn; + if (metadata_to_lsn > lsn) + lsn= metadata_to_lsn; msg("mariabackup: The latest check point (for incremental): '" LSN_PF "'", metadata_to_lsn); } @@ -5592,7 +5600,7 @@ fail: /* get current checkpoint_lsn */ { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); mysql_mutex_lock(&recv_sys.mutex); dberr_t err = recv_sys.find_checkpoint(); log_sys.latch.wr_unlock(); @@ -5653,7 +5661,7 @@ fail: } /* label it */ - recv_sys.file_checkpoint = log_sys.next_checkpoint_lsn; + recv_sys.file_checkpoint = log_sys.last_checkpoint_lsn; log_hdr_init(); /* Write log header*/ if (ds_write(dst_log_file, log_hdr_buf, 12288)) { @@ -5684,7 +5692,7 @@ fail: mysql_mutex_lock(&recv_sys.mutex); backup_log_parse = recv_sys.get_backup_parser(); - recv_sys.lsn = log_sys.next_checkpoint_lsn; + recv_sys.lsn = log_sys.last_checkpoint_lsn; const bool log_copy_failed = xtrabackup_copy_logfile(true); @@ -5743,7 +5751,7 @@ fail: backup_datasinks.destroy(); msg("Redo log (from LSN " LSN_PF " to " LSN_PF ") was copied.", - log_sys.next_checkpoint_lsn, recv_sys.lsn); + log_sys.last_checkpoint_lsn.load(), recv_sys.lsn); xb_filters_free(); xb_data_files_close(); diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 5452b56db6f..1cc6459d59a 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -28,9 +28,6 @@ SET(HEADERS mariadb_capi_rename.h pack.h my_byteorder.h - byte_order_generic.h - byte_order_generic_x86.h - byte_order_generic_x86_64.h little_endian.h big_endian.h mysql_time.h diff --git a/include/byte_order_generic.h b/include/byte_order_generic.h deleted file mode 100644 index d2b729a241d..00000000000 --- a/include/byte_order_generic.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2020, 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 Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -/* - Endianness-independent definitions for architectures other - than the x86 architecture. -*/ -#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) |\ - ((int16) ((int16) (A)[1]) << 8)) -#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ - (((uint32) 255L << 24) | \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0])) : \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0]))) -#define sint4korr(A) (int32) (((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1]) << 8)) |\ - (((uint32) ((uchar) (A)[2]) << 16)) |\ - (((uint32) ((uchar) (A)[3]) << 24))) -#define sint8korr(A) (longlong) uint8korr(A) -#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) |\ - ((uint16) ((uchar) (A)[1]) << 8)) -#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16)) -#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16) |\ - (((uint32) ((uchar) (A)[3])) << 24)) -#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16) |\ - (((uint32) ((uchar) (A)[3])) << 24)) |\ - (((ulonglong) ((uchar) (A)[4])) << 32)) -#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) | \ - (((uint32) ((uchar) (A)[1])) << 8) | \ - (((uint32) ((uchar) (A)[2])) << 16) | \ - (((uint32) ((uchar) (A)[3])) << 24)) | \ - (((ulonglong) ((uchar) (A)[4])) << 32) | \ - (((ulonglong) ((uchar) (A)[5])) << 40)) -#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16) |\ - (((uint32) ((uchar) (A)[3])) << 24)) |\ - (((ulonglong) (((uint32) ((uchar) (A)[4])) |\ - (((uint32) ((uchar) (A)[5])) << 8) |\ - (((uint32) ((uchar) (A)[6])) << 16) |\ - (((uint32) ((uchar) (A)[7])) << 24))) <<\ - 32)) -#define int2store(T,A) do { uint def_temp= (uint) (A) ;\ - *((uchar*) (T))= (uchar)(def_temp); \ - *((uchar*) (T)+1)=(uchar)((def_temp >> 8)); \ - } while(0) -#define int3store(T,A) do { /*lint -save -e734 */\ - *((uchar*)(T))=(uchar) ((A));\ - *((uchar*) (T)+1)=(uchar) (((A) >> 8));\ - *((uchar*)(T)+2)=(uchar) (((A) >> 16)); \ - /*lint -restore */} while(0) -#define int4store(T,A) do { *((char *)(T))=(char) ((A));\ - *(((char *)(T))+1)=(char) (((A) >> 8));\ - *(((char *)(T))+2)=(char) (((A) >> 16));\ - *(((char *)(T))+3)=(char) (((A) >> 24));\ - } while(0) -#define int5store(T,A) do { *((char *)(T))= (char)((A)); \ - *(((char *)(T))+1)= (char)(((A) >> 8)); \ - *(((char *)(T))+2)= (char)(((A) >> 16)); \ - *(((char *)(T))+3)= (char)(((A) >> 24)); \ - *(((char *)(T))+4)= (char)(((A) >> 32)); \ - } while(0) -#define int6store(T,A) do { *((char *)(T))= (char)((A)); \ - *(((char *)(T))+1)= (char)(((A) >> 8)); \ - *(((char *)(T))+2)= (char)(((A) >> 16)); \ - *(((char *)(T))+3)= (char)(((A) >> 24)); \ - *(((char *)(T))+4)= (char)(((A) >> 32)); \ - *(((char *)(T))+5)= (char)(((A) >> 40)); \ - } while(0) -#define int8store(T,A) do { uint def_temp= (uint) (A), \ - def_temp2= (uint) ((A) >> 32); \ - int4store((T),def_temp); \ - int4store((T+4),def_temp2);\ - } while(0) diff --git a/include/byte_order_generic_x86.h b/include/byte_order_generic_x86.h deleted file mode 100644 index c47564478c6..00000000000 --- a/include/byte_order_generic_x86.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2020, 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 Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -/* - Optimized function-like macros for the x86 architecture (_WIN32 included). -*/ - -#define sint2korr(A) (*((const int16 *) (A))) -#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ - (((uint32) 255L << 24) | \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0])) : \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0]))) -#define sint4korr(A) (*((const long *) (A))) -#define uint2korr(A) (*((const uint16 *) (A))) -#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16)) -#define uint4korr(A) (*((const uint32 *) (A))) -#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16) |\ - (((uint32) ((uchar) (A)[3])) << 24)) |\ - (((ulonglong) ((uchar) (A)[4])) << 32)) -#define uint6korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) | \ - (((uint32) ((uchar) (A)[1])) << 8) | \ - (((uint32) ((uchar) (A)[2])) << 16) | \ - (((uint32) ((uchar) (A)[3])) << 24)) | \ - (((ulonglong) ((uchar) (A)[4])) << 32) | \ - (((ulonglong) ((uchar) (A)[5])) << 40)) -#define uint8korr(A) (*((const ulonglong *) (A))) -#define sint8korr(A) (*((const longlong *) (A))) - -#define int2store(T,A) *((uint16*) (T))= (uint16) (A) -#define int3store(T,A) do { *(T)= (uchar) ((A));\ - *(T+1)=(uchar) (((uint) (A) >> 8));\ - *(T+2)=(uchar) (((A) >> 16));\ - } while (0) -#define int4store(T,A) *((long *) (T))= (long) (A) -#define int5store(T,A) do { *(T)= (uchar)((A));\ - *((T)+1)=(uchar) (((A) >> 8));\ - *((T)+2)=(uchar) (((A) >> 16));\ - *((T)+3)=(uchar) (((A) >> 24));\ - *((T)+4)=(uchar) (((A) >> 32));\ - } while(0) -#define int6store(T,A) do { *(T)= (uchar)((A)); \ - *((T)+1)=(uchar) (((A) >> 8)); \ - *((T)+2)=(uchar) (((A) >> 16)); \ - *((T)+3)=(uchar) (((A) >> 24)); \ - *((T)+4)=(uchar) (((A) >> 32)); \ - *((T)+5)=(uchar) (((A) >> 40)); \ - } while(0) -#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A) -typedef union { - double v; - long m[2]; -} doubleget_union; -#define doubleget(V,M) \ -do { doubleget_union _tmp; \ - _tmp.m[0] = *((const long*)(M)); \ - _tmp.m[1] = *(((const long*) (M))+1); \ - (V) = _tmp.v; } while(0) -#define doublestore(T,V) \ -do { *((long *) T) = ((const doubleget_union *)&V)->m[0]; \ - *(((long *) T)+1) = ((const doubleget_union *)&V)->m[1]; \ - } while (0) -#define float4get(V,M) \ -do { *((float *) &(V)) = *((const float*) (M)); } while(0) -#define float8get(V,M) doubleget((V),(M)) -#define float4store(V,M) memcpy((uchar*)(V), (uchar*)(&M), sizeof(float)) -#define floatstore(T,V) memcpy((uchar*)(T), (uchar*)(&V), sizeof(float)) -#define floatget(V,M) memcpy((uchar*)(&V),(uchar*) (M), sizeof(float)) -#define float8store(V,M) doublestore((V),(M)) diff --git a/include/byte_order_generic_x86_64.h b/include/byte_order_generic_x86_64.h deleted file mode 100644 index 305ba2b430e..00000000000 --- a/include/byte_order_generic_x86_64.h +++ /dev/null @@ -1,125 +0,0 @@ -/* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2020, 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 Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -/* - Optimized function-like macros for the x86 architecture (_WIN32 included). -*/ - -#define sint2korr(A) (int16) (*((int16 *) (A))) -#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \ - (((uint32) 255L << 24) | \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0])) : \ - (((uint32) (uchar) (A)[2]) << 16) |\ - (((uint32) (uchar) (A)[1]) << 8) | \ - ((uint32) (uchar) (A)[0]))) -#define sint4korr(A) (int32) (*((int32 *) (A))) -#define uint2korr(A) (uint16) (*((uint16 *) (A))) -#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) |\ - (((uint32) ((uchar) (A)[1])) << 8) |\ - (((uint32) ((uchar) (A)[2])) << 16)) -#define uint4korr(A) (uint32) (*((uint32 *) (A))) - - -static inline ulonglong uint5korr(const void *p) -{ - ulonglong a= *(uint32 *) p; - ulonglong b= *(4 + (uchar *) p); - return a | (b << 32); -} -static inline ulonglong uint6korr(const void *p) -{ - ulonglong a= *(uint32 *) p; - ulonglong b= *(uint16 *) (4 + (char *) p); - return a | (b << 32); -} - -#define uint8korr(A) (ulonglong) (*((ulonglong *) (A))) -#define sint8korr(A) (longlong) (*((longlong *) (A))) - -#define int2store(T,A) do { uchar *pT= (uchar*)(T);\ - *((uint16*)(pT))= (uint16) (A);\ - } while (0) - -#define int3store(T,A) do { *(T)= (uchar) ((A));\ - *(T+1)=(uchar) (((uint) (A) >> 8));\ - *(T+2)=(uchar) (((A) >> 16));\ - } while (0) - -#define int4store(T,A) do { uchar *pT= (uchar*)(T);\ - *((uint32 *) (pT))= (uint32) (A); \ - } while (0) - -#define int5store(T,A) do { uchar *pT= (uchar*)(T);\ - *((uint32 *) (pT))= (uint32) (A); \ - *((pT)+4)=(uchar) (((A) >> 32));\ - } while (0) - -#define int6store(T,A) do { uchar *pT= (uchar*)(T);\ - *((uint32 *) (pT))= (uint32) (A); \ - *((uint16*)(pT+4))= (uint16) (A >> 32);\ - } while (0) - -#define int8store(T,A) do { uchar *pT= (uchar*)(T);\ - *((ulonglong *) (pT))= (ulonglong) (A);\ - } while(0) - -#if defined(__GNUC__) - -#define HAVE_mi_uint5korr -#define HAVE_mi_uint6korr -#define HAVE_mi_uint7korr -#define HAVE_mi_uint8korr - -/* Read numbers stored in high-bytes-first order */ - -static inline ulonglong mi_uint5korr(const void *p) -{ - ulonglong a= *(uint32 *) p; - ulonglong b= *(4 + (uchar *) p); - ulonglong v= (a | (b << 32)) << 24; - asm ("bswapq %0" : "=r" (v) : "0" (v)); - return v; -} - -static inline ulonglong mi_uint6korr(const void *p) -{ - ulonglong a= *(uint32 *) p; - ulonglong b= *(uint16 *) (4 + (char *) p); - ulonglong v= (a | (b << 32)) << 16; - asm ("bswapq %0" : "=r" (v) : "0" (v)); - return v; -} - -static inline ulonglong mi_uint7korr(const void *p) -{ - ulonglong a= *(uint32 *) p; - ulonglong b= *(uint16 *) (4 + (char *) p); - ulonglong c= *(6 + (uchar *) p); - ulonglong v= (a | (b << 32) | (c << 48)) << 8; - asm ("bswapq %0" : "=r" (v) : "0" (v)); - return v; -} - -static inline ulonglong mi_uint8korr(const void *p) -{ - ulonglong v= *(ulonglong *) p; - asm ("bswapq %0" : "=r" (v) : "0" (v)); - return v; -} - -#endif diff --git a/include/my_base.h b/include/my_base.h index 8fdd1397ff0..1768be00940 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -227,13 +227,14 @@ enum ha_extra_function { that we are starting an ordered index scan. Needed by Spider */ HA_EXTRA_STARTING_ORDERED_INDEX_SCAN, - /** Start writing rows during ALTER TABLE...ALGORITHM=COPY. */ - HA_EXTRA_BEGIN_ALTER_COPY, - /** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */ - HA_EXTRA_END_ALTER_COPY, - /** Abort of writing rows during ALTER TABLE..ALGORITHM=COPY or - CREATE..SELCT */ - HA_EXTRA_ABORT_ALTER_COPY + /** Start copying in ALTER TABLE...ALGORITHM=COPY or CREATE TABLE..SELECT */ + HA_EXTRA_BEGIN_COPY, + /** Start writing rows during ALTER IGNORE TABLE..ALGORITHM=COPY */ + HA_EXTRA_BEGIN_ALTER_IGNORE_COPY, + /** Finish HA_EXTRA_BEGIN_COPY or HA_EXTRA_BEGIN_ALTER_IGNORE_COPY */ + HA_EXTRA_END_COPY, + /** Abort HA_EXTRA_BEGIN_COPY or HA_EXTRA_BEGIN_ALTER_IGNORE_COPY */ + HA_EXTRA_ABORT_COPY }; /* Compatible option, to be deleted in 6.0 */ diff --git a/include/my_byteorder.h b/include/my_byteorder.h index 2939ae07353..10d92a93109 100644 --- a/include/my_byteorder.h +++ b/include/my_byteorder.h @@ -19,32 +19,269 @@ #include /* - Macro for reading 32-bit integer from network byte order (big-endian) - from an unaligned memory location. + Byte-swap helpers. */ -#define int4net(A) (int32) (((uint32) ((uchar) (A)[3])) | \ - (((uint32) ((uchar) (A)[2])) << 8) | \ - (((uint32) ((uchar) (A)[1])) << 16) | \ - (((uint32) ((uchar) (A)[0])) << 24)) - -/* - Function-like macros for reading and storing in machine independent - format (low byte first). There are 'korr' (assume 'corrector') variants - for integer types, but 'get' (assume 'getter') for floating point types. -*/ -#if (defined(__i386__) || defined(_M_IX86)) && !defined(WITH_UBSAN) -#define MY_BYTE_ORDER_ARCH_OPTIMIZED -#include "byte_order_generic_x86.h" -#elif (defined(__x86_64__) || defined (_M_X64)) && !defined(WITH_UBSAN) -#include "byte_order_generic_x86_64.h" +#ifdef _MSC_VER +# include /* _byteswap_* */ +# define MY_BSWAP16(x) _byteswap_ushort(x) +# define MY_BSWAP32(x) _byteswap_ulong(x) +# define MY_BSWAP64(x) _byteswap_uint64(x) +#elif defined __GNUC__ +# define MY_BSWAP16(x) __builtin_bswap16(x) +# define MY_BSWAP32(x) __builtin_bswap32(x) +# define MY_BSWAP64(x) __builtin_bswap64(x) #else -#include "byte_order_generic.h" +# error provide byteswap intrinsics #endif /* - Function-like macros for reading and storing in machine format from/to - short/long to/from some place in memory V should be a variable (not on - a register) and M a pointer to byte. + Some inline functions to convert between little-endian and host byte order + in the spirit of htons/htonl et al. +*/ + +static inline uint16 my_letoh16(uint16 x) +{ +#ifdef WORDS_BIGENDIAN + return MY_BSWAP16(x); +#else + return x; +#endif +} + +static inline uint16 my_betoh16(uint16 x) +{ +#ifdef WORDS_BIGENDIAN + return x; +#else + return MY_BSWAP16(x); +#endif +} + +static inline uint32 my_letoh32(uint32 x) +{ +#ifdef WORDS_BIGENDIAN + return MY_BSWAP32(x); +#else + return x; +#endif +} + +static inline uint32 my_betoh32(uint32 x) +{ +#ifdef WORDS_BIGENDIAN + return x; +#else + return MY_BSWAP32(x); +#endif +} + +static inline uint64 my_letoh64(uint64 x) +{ +#ifdef WORDS_BIGENDIAN + return MY_BSWAP64(x); +#else + return x; +#endif +} + +static inline uint64 my_betoh64(uint64 x) +{ +#ifdef WORDS_BIGENDIAN + return x; +#else + return MY_BSWAP64(x); +#endif +} + +#define my_htole16(x) my_letoh16(x) +#define my_htobe16(x) my_betoh16(x) +#define my_htole32(x) my_letoh32(x) +#define my_htobe32(x) my_betoh32(x) +#define my_htole64(x) my_letoh64(x) +#define my_htobe64(x) my_betoh64(x) + +/* + Inline functions for reading/storing little endian integers from/to + potentially unaligned memory. + + memcpy() is used to avoid unaligned access. On most platforms the compiler + will optimize memcpy to a single instruction. +*/ + +static inline uint16 uint2korr(const void *p) +{ + uint16 ret; + memcpy(&ret, p, 2); + return my_letoh16(ret); +} + +static inline uint32 uint4korr(const void *p) +{ + uint32 ret; + memcpy(&ret, p, 4); + return my_letoh32(ret); +} + +static inline uint64 uint8korr(const void *p) +{ + uint64 ret; + memcpy(&ret, p, 8); + return my_letoh64(ret); +} + +static inline int16 sint2korr(const void *p) +{ + return (int16) uint2korr(p); +} + +static inline int32 sint4korr(const void *p) +{ + return (int32) uint4korr(p); +} + +static inline longlong sint8korr(const void *p) +{ + return (longlong) uint8korr(p); +} + +static inline void int2store(void *t, ulonglong a) +{ + uint16 v= my_htole16((uint16) a); + memcpy(t, &v, 2); +} + +static inline void int4store(void *t, ulonglong a) +{ + uint32 v= my_htole32((uint32) a); + memcpy(t, &v, 4); +} + +static inline void int8store(void *t, ulonglong a) +{ + uint64 v= my_htole64((uint64) a); + memcpy(t, &v, 8); +} + +/* + Odd-width and sign-extending functions. These use only individual + byte accesses or delegate to the even-width functions above, so they + are correct on any host endianness without further #ifdefs. +*/ + + +static inline uint32 uint3korr(const void *p) +{ + return (uint32) uint2korr(p) | ((uint32) ((const uchar *) p)[2] << 16); +} + +static inline int32 sint3korr(const void *p) +{ + uint32 v = uint3korr(p); + /* + Shift left to move sign bit into MSB position, then arithmetic + right shift to sign-extend back. + */ + return ((int32)(v << 8)) >> 8; +} + +static inline ulonglong uint5korr(const void *p) +{ + return (ulonglong) uint4korr(p) | ((ulonglong) ((const uchar *) p)[4] << 32); +} + +static inline ulonglong uint6korr(const void *p) +{ + return (ulonglong) uint4korr(p) | + ((ulonglong) uint2korr((const uchar *) p + 4) << 32); +} + +static inline void int3store(void *t, ulonglong a) +{ + uchar *p= (uchar *) t; + int2store(t, a); + p[2]= (uchar) (a >> 16); +} + +static inline void int5store(void *t, ulonglong a) +{ + uchar *p= (uchar *) t; + int4store(t, a); + p[4]= (uchar) (a >> 32); +} + +static inline void int6store(void *t, ulonglong a) +{ + uchar *p= (uchar *) t; + int4store(t, a); + int2store(p + 4, a >> 32); +} + +/* + mi_uint*korr: read an N-byte unsigned integer stored in big-endian + order, as used by MyISAM. + Below are optimizations for little-endian architectures. +*/ + +#ifndef WORDS_BIGENDIAN + +#define HAVE_mi_uint5korr +#define HAVE_mi_uint6korr +#define HAVE_mi_uint7korr +#define HAVE_mi_uint8korr + +static inline ulonglong mi_uint5korr(const void *p) +{ + uint32 lo; + memcpy(&lo, (const uchar *) p + 1, 4); + lo= MY_BSWAP32(lo); + return ((ulonglong) ((const uchar *)p)[0]) << 32 | lo; +} + +static inline ulonglong mi_uint6korr(const void *p) +{ + uint32 a; + uint16 b; + ulonglong v; + memcpy(&a, p, 4); + memcpy(&b, (const uchar *) p + 4, 2); + v= ((ulonglong) a | ((ulonglong) b << 32)) << 16; + return MY_BSWAP64(v); +} + +static inline ulonglong mi_uint7korr(const void *p) +{ + uint32 a; + uint16 b; + ulonglong v; + ulonglong c= ((const uchar *)p)[6]; + memcpy(&a, p, 4); + memcpy(&b, (const uchar *) p + 4, 2); + v= ((ulonglong)a | ((ulonglong)b << 32) | (c << 48)) << 8; + return MY_BSWAP64(v); +} + +static inline ulonglong mi_uint8korr(const void *p) +{ + ulonglong ret; + memcpy(&ret, p, 8); + return MY_BSWAP64(ret); +} +#endif /* !WORDS_BIGENDIAN */ + +/* + Read a 32-bit integer from network byte order (big-endian) + from an unaligned memory location. +*/ +static inline int32 int4net(const void *p) +{ + int32 ret; + memcpy(&ret, p, 4); + return (int32)my_betoh32(ret); +} + +/* + Some macros for reading doubles and floats (clean, do not assume alignment) + These are defined in big_endian.h and little_endian.h */ #ifdef WORDS_BIGENDIAN #include "big_endian.h" diff --git a/include/my_cpu.h b/include/my_cpu.h index 2b34e03fce3..028dc05bd08 100644 --- a/include/my_cpu.h +++ b/include/my_cpu.h @@ -59,8 +59,8 @@ #define HMT_high() #endif -#if defined __i386__ || defined __x86_64__ || defined _WIN32 -# define HAVE_PAUSE_INSTRUCTION /* added in Intel Pentium 4 */ +#if defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64 +# define HAVE_PAUSE_INSTRUCTION /* no-op repurposed in Intel Pentium 4 */ #endif #ifdef _WIN32 diff --git a/include/my_virtual_mem.h b/include/my_virtual_mem.h index 8f9f6660e3b..b4f26ca979c 100644 --- a/include/my_virtual_mem.h +++ b/include/my_virtual_mem.h @@ -24,9 +24,9 @@ extern "C" { #endif -# ifdef _WIN32 +#ifdef _WIN32 char *my_virtual_mem_reserve(size_t *size); -# endif +#endif char *my_virtual_mem_commit(char *ptr, size_t size); void my_virtual_mem_decommit(char *ptr, size_t size); void my_virtual_mem_release(char *ptr, size_t size); diff --git a/libmysqld/libmysql.c b/libmysqld/libmysql.c index 11f45e03273..d5754090ce5 100644 --- a/libmysqld/libmysql.c +++ b/libmysqld/libmysql.c @@ -4503,13 +4503,11 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt) max_length */ MYSQL_BIND *my_bind, *end; - MYSQL_FIELD *field; bzero((char*) stmt->bind, sizeof(*stmt->bind)* stmt->field_count); - for (my_bind= stmt->bind, end= my_bind + stmt->field_count, - field= stmt->fields; + for (my_bind= stmt->bind, end= my_bind + stmt->field_count; my_bind < end ; - my_bind++, field++) + my_bind++) { my_bind->buffer_type= MYSQL_TYPE_NULL; my_bind->buffer_length=1; diff --git a/mysql-test/main/func_json.result b/mysql-test/main/func_json.result index 998b1281431..57520346c4f 100644 --- a/mysql-test/main/func_json.result +++ b/mysql-test/main/func_json.result @@ -676,6 +676,8 @@ JSON_SEARCH('{"foo":"bar"}', 'all' , @str, '%', @path) SELECT JSON_VALUE('[{"foo": 1},"bar"]', '$[*][0]'); JSON_VALUE('[{"foo": 1},"bar"]', '$[*][0]') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' CREATE TABLE t1 (f INT NOT NULL); INSERT INTO t1 VALUES (0); SELECT JSON_KEYS(f) FROM t1 ORDER BY 1; @@ -1470,6 +1472,8 @@ SET COLLATION_CONNECTION= ucs2_unicode_ci; SELECT JSON_VALUE('["foo"]', '$**[0]') AS f; f NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' SET @@COLLATION_CONNECTION= @old_collation_connection; # # MDEV-32587 JSON_VALID fail to validate integer zero in scientific notation @@ -1782,6 +1786,26 @@ null<=>json_extract('1',json_object(null,'{ }',null,null),'{}') Warnings: Warning 4042 Syntax error in JSON path in argument 2 to function 'json_extract' at position 1 # End of 10.6 tests +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('["a",1]', '$') AS j) AS t; +json_extract(t.j, '$') +["a", 1] +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('{"key":"value"}', '$') AS j) AS t; +json_extract(t.j, '$') +{"key": "value"} +SELECT json_extract(t.j, '$[0]', '$[1]') +FROM (SELECT json_extract('[{"a":1},{"b":2},{"c":3}]', '$') AS j) AS t; +json_extract(t.j, '$[0]', '$[1]') +[{"a": 1}, {"b": 2}] +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('{"name":"Ä Ö Ü ß","city":"München"}', '$') AS j) AS t; +json_extract(t.j, '$') +{"name": "Ä Ö Ü ß", "city": "München"} +SELECT json_extract(t.j, '$.name') +FROM (SELECT json_extract('{"name":"日本語テスト","val":[1,2]}', '$') AS j) AS t; +json_extract(t.j, '$.name') +"日本語テスト" # # MDEV-35614 JSON_UNQUOTE doesn't work with emojis # @@ -2398,6 +2422,8 @@ SET @json= '[ SELECT JSON_VALUE(@json, '$[0][1 to 2].key1'); JSON_VALUE(@json, '$[0][1 to 2].key1') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' SET @json='{ "A": [0, [1, 2, 3], @@ -2414,7 +2440,7 @@ SET @json='{ }'; SELECT JSON_QUERY(@json, '$.A[-2][-3 to -1]'); JSON_QUERY(@json, '$.A[-2][-3 to -1]') -NULL +[13, 14] SET @json= '[ [1, {"key1": "value1"}, 3], [false, 5, 6], @@ -2563,6 +2589,8 @@ SET @json1= '[ SELECT JSON_VALUE(@json1, '$[2][1 to 2].key1'); JSON_VALUE(@json1, '$[2][1 to 2].key1') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' SET @json= '[ [1.1, {"key1": "value1"}, 3], [false, 5, 6], @@ -2573,9 +2601,13 @@ SET @json= '[ SELECT JSON_VALUE(@json, '$[*][0]'); JSON_VALUE(@json, '$[*][0]') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' SELECT JSON_VALUE(@json, '$[2 to 3][0]'); JSON_VALUE(@json, '$[2 to 3][0]') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' # # MDEV-28072: JSON_EXTRACT has inconsistent behavior with '0' value in # json path (when range is used) @@ -2784,6 +2816,19 @@ S1A1 SELECT JSON_VALUE('{"a":[1,2]}', '$.a[*]'); JSON_VALUE('{"a":[1,2]}', '$.a[*]') NULL +Warnings: +Warning 4044 Wildcards or range in JSON path not allowed in argument 2 to function 'json_value' +# +# MDEV-37640: Crash at String::append with json_normalize +# +SELECT ( WITH x AS ( WITH x AS ( SELECT 1.000000 ) SELECT ( REPEAT ( ( json_normalize ( ' -1' ) ) , 357 ) ) x ) SELECT x FROM x WHERE x IN ( x , x ) ); +( WITH x AS ( WITH x AS ( SELECT 1.000000 ) SELECT ( REPEAT ( ( json_normalize ( ' -1' ) ) , 357 ) ) x ) SELECT x FROM x WHERE x IN ( x , x ) ) +-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0-1.0E0 +# +# MDEV-37640: Crash in JSON_KEYS +# +SELECT JSON_SET('{"c":4}', '$.a', 5) AS x HAVING (x IN (JSON_KEYS(x), ',')); +x # End of 10.11 Test # # MDEV-32007: JSON_VALUE and JSON_EXTRACT doesn't handle dash (-) @@ -4995,6 +5040,8 @@ Warning 4037 Unexpected end of JSON text in argument 1 to function 'json_key_val SELECT JSON_KEY_VALUE('[1,2,3]', ''); JSON_KEY_VALUE('[1,2,3]', '') NULL +Warnings: +Warning 4041 Unexpected end of JSON path in argument 2 to function 'json_key_value' SELECT JSON_KEY_VALUE('[1,2,3]', NULL); JSON_KEY_VALUE('[1,2,3]', NULL) NULL @@ -5044,6 +5091,8 @@ k v id SELECT JSON_KEY_VALUE('[]', '[0]'); JSON_KEY_VALUE('[]', '[0]') NULL +Warnings: +Warning 4042 Syntax error in JSON path in argument 2 to function 'json_key_value' at position 1 SELECT JSON_KEY_VALUE('[1, 2, 3]', '$[0]'); JSON_KEY_VALUE('[1, 2, 3]', '$[0]') NULL diff --git a/mysql-test/main/func_json.test b/mysql-test/main/func_json.test index fabbeede953..cd6ab43412c 100644 --- a/mysql-test/main/func_json.test +++ b/mysql-test/main/func_json.test @@ -1228,6 +1228,23 @@ select null<=>json_extract('1',json_object(null,'{ }',null,null),'{}'); --echo # End of 10.6 tests +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('["a",1]', '$') AS j) AS t; + +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('{"key":"value"}', '$') AS j) AS t; + +# Multi-path extraction through derived table +SELECT json_extract(t.j, '$[0]', '$[1]') +FROM (SELECT json_extract('[{"a":1},{"b":2},{"c":3}]', '$') AS j) AS t; + +# UTF-8 content through derived table +SELECT json_extract(t.j, '$') +FROM (SELECT json_extract('{"name":"Ä Ö Ü ß","city":"München"}', '$') AS j) AS t; + +SELECT json_extract(t.j, '$.name') +FROM (SELECT json_extract('{"name":"日本語テスト","val":[1,2]}', '$') AS j) AS t; + --echo # --echo # MDEV-35614 JSON_UNQUOTE doesn't work with emojis --echo # @@ -2016,6 +2033,18 @@ COLUMNS(NAME VARCHAR(30) PATH '$.NAME')) AS t_sz; SELECT JSON_VALUE('{"a":[1,2]}', '$.a[*]'); +--echo # +--echo # MDEV-37640: Crash at String::append with json_normalize +--echo # + +SELECT ( WITH x AS ( WITH x AS ( SELECT 1.000000 ) SELECT ( REPEAT ( ( json_normalize ( ' -1' ) ) , 357 ) ) x ) SELECT x FROM x WHERE x IN ( x , x ) ); + +--echo # +--echo # MDEV-37640: Crash in JSON_KEYS +--echo # + +SELECT JSON_SET('{"c":4}', '$.a', 5) AS x HAVING (x IN (JSON_KEYS(x), ',')); + --echo # End of 10.11 Test --echo # diff --git a/mysql-test/main/gis-precise.result b/mysql-test/main/gis-precise.result index 242fa2eb5ef..a454fbf00ba 100644 --- a/mysql-test/main/gis-precise.result +++ b/mysql-test/main/gis-precise.result @@ -389,7 +389,7 @@ result MULTIPOINT(7 5,7 5.142857142857142,5.899999999999998 5.300000000000001,5.799999999999997 5.600000000000001,3 7) SELECT ST_CROSSES( GEOMETRYFROMTEXT(' POLYGON( (3 5, 2 4, 2 5, 3 5) ) ') , POLYGONFROMTEXT(' POLYGON((2 4,3 4,3 5,2 5,2 4)) ')) as result; result -0 +NULL SELECT ST_WITHIN( POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 2 0 , 1 0, 2 4 , 0 4, 0 5) ) ') , POLYGONFROMTEXT(' POLYGON( (0 5, 3 5, 3 4, 1 4 , 1 3 , 3 3 , 3 0 , 0 0 , 0 5), ( 1 1 , 2 1 , 2 2 , 1 2 , 1 1 ) ) ') ) as result; result 0 @@ -868,3 +868,15 @@ ST_INTERSECTION( ST_MULTIPOLYGONFROMTEXT(' MULTIPOLYGON(((3.8571428571428568 2.857142857142857,5.571428571428571 4.571428571428571,9 4,3.8571428571428568 2.857142857142857)),((4.5 4.75,3 5,4.6 7.4,6 6,4.5 4.75))) '), ST_MULTIPOLYGONFROMTEXT(' MULTIPOLYGON(((3 4,3 5,2 5,2 7,5 4,3 4),(5 4,7.4 7,8 7,8 4,5 4))) ') )) as V; V 3 +# +# MDEV-36058 ST_CROSSES returns 0 instead of NULL. +# +SELECT ST_CROSSES( ST_GEOMFROMTEXT('point(1 1)'), st_geomfromtext('point(1 1)') ) a; +a +NULL +SELECT ST_CROSSES( ST_GEOMFROMTEXT('POLYGON ((59 18,67 18,67 13,59 13,59 18)) '), st_geomfromtext('polygon((2 2,2 4, 4 2,2 2))') ) a; +a +NULL +SELECT ST_CROSSES( ST_GEOMFROMTEXT('POLYGON ((59 18,67 18,67 13,59 13,59 18)) '), st_geomfromtext('point(1 1)') ) a; +a +NULL diff --git a/mysql-test/main/gis-precise.test b/mysql-test/main/gis-precise.test index 4f84589c999..abf9ccb9394 100644 --- a/mysql-test/main/gis-precise.test +++ b/mysql-test/main/gis-precise.test @@ -477,7 +477,6 @@ set @sarajevo = ST_GeomFromText('POINT(18.413076 43.856258)'); SELECT TRUNCATE(ST_Distance_Sphere(@zenica, @sarajevo), 10); SELECT TRUNCATE(ST_Distance_Sphere(@sarajevo, @zenica), 10); - --echo # --echo # MDEV-31499 Assertion `(0)' failed in Gis_geometry_collection::init_from_opresult. --echo # @@ -486,3 +485,12 @@ SELECT ST_NUMGEOMETRIES( ST_INTERSECTION( ST_MULTIPOLYGONFROMTEXT(' MULTIPOLYGON(((3.8571428571428568 2.857142857142857,5.571428571428571 4.571428571428571,9 4,3.8571428571428568 2.857142857142857)),((4.5 4.75,3 5,4.6 7.4,6 6,4.5 4.75))) '), ST_MULTIPOLYGONFROMTEXT(' MULTIPOLYGON(((3 4,3 5,2 5,2 7,5 4,3 4),(5 4,7.4 7,8 7,8 4,5 4))) ') )) as V; +--echo # +--echo # MDEV-36058 ST_CROSSES returns 0 instead of NULL. +--echo # + + +SELECT ST_CROSSES( ST_GEOMFROMTEXT('point(1 1)'), st_geomfromtext('point(1 1)') ) a; +SELECT ST_CROSSES( ST_GEOMFROMTEXT('POLYGON ((59 18,67 18,67 13,59 13,59 18)) '), st_geomfromtext('polygon((2 2,2 4, 4 2,2 2))') ) a; +SELECT ST_CROSSES( ST_GEOMFROMTEXT('POLYGON ((59 18,67 18,67 13,59 13,59 18)) '), st_geomfromtext('point(1 1)') ) a; + diff --git a/mysql-test/main/gis.result b/mysql-test/main/gis.result index d93a25efff9..1ed1a5f7dd7 100644 --- a/mysql-test/main/gis.result +++ b/mysql-test/main/gis.result @@ -1816,7 +1816,7 @@ exp # SELECT ST_GEOMETRYTYPE(ST_PointOnSurface(ST_PolyFromText('POLYGON((-70.916 42.1002,-70.9468 42.0946,-70.9754 42.0875,-70.9749 42.0879,-70.9759 42.0897,-70.916 42.1002))'))) as exp; exp -NULL +POINT # # MDEV-7529 GIS: ST_Relate returns unexpected results for POINT relations # @@ -5505,6 +5505,13 @@ SELECT ST_DISTANCE_SPHERE(st_geomfromtext('linestring( 2 2, 2 8) '), ST_GeomFrom ERROR HY000: Calling geometry function st_distance_sphere with unsupported types of arguments. # End of 10.5 tests # +# MDEV-35766 ST_PointOnSurface returns NULL with Polygon in some case. +# +SELECT ST_ASTEXT(ST_POINTONSURFACE(ST_GeomFromText('POLYGON((-1 0, 1 2, 1 0, -1 0))'))) as T; +T +POINT(0.5 1) +# End of 10.6 tests +# # Start of 11.5 tests # # diff --git a/mysql-test/main/gis.test b/mysql-test/main/gis.test index 88200a61faf..8a4fc1b00b6 100644 --- a/mysql-test/main/gis.test +++ b/mysql-test/main/gis.test @@ -3512,6 +3512,13 @@ SELECT ST_DISTANCE_SPHERE(st_geomfromtext('linestring( 2 2, 2 8) '), ST_GeomFrom --echo # End of 10.5 tests +--echo # +--echo # MDEV-35766 ST_PointOnSurface returns NULL with Polygon in some case. +--echo # +SELECT ST_ASTEXT(ST_POINTONSURFACE(ST_GeomFromText('POLYGON((-1 0, 1 2, 1 0, -1 0))'))) as T; + +--echo # End of 10.6 tests + --echo # --echo # Start of 11.5 tests --echo # diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result index 9dd63bfdd4a..24690127b66 100644 --- a/mysql-test/main/having.result +++ b/mysql-test/main/having.result @@ -1020,3 +1020,27 @@ SET optimizer_trace= @save_optimizer_trace; # # End of 10.11 tests # +# +# MDEV-38070 wrong resultset with having and or condition +# +CREATE TABLE t1 ( a int, PRIMARY KEY (a)) ; +INSERT INTO t1 values (3),(4),(5),(6),(7); +CREATE TABLE t2 (b int , c TIMESTAMP ); +INSERT INTO t2 VALUES (1,'2025-11-06 09:24:27'),(1,'2025-11-06 09:24:27'), +(2,'2025-11-06 09:24:27'),(2,'2025-11-06 09:24:27'),(3,'2025-11-06 09:24:27'), +(3,'2025-11-06 09:24:27'),(4,'2025-11-06 09:24:27'),(4,'2025-11-06 09:24:27'), +(5,'2025-11-06 09:24:27'),(5,'2025-11-06 09:24:27'),(6,'2025-11-06 09:24:27'), +(6,'2025-11-06 09:24:27'),(7,'2025-11-06 11:24:27'),(7,'2025-11-06 11:24:27'); +SELECT t1.a, tbl.b +FROM t1 +JOIN ( SELECT t2.b as id2, max(t2.c) AS b FROM t2 GROUP BY t2.b ) tbl +ON tbl.id2 = t1.a +GROUP BY t1.a +HAVING (tbl.b < '2025-11-06 10:40:00'); +a b +3 2025-11-06 09:24:27 +4 2025-11-06 09:24:27 +5 2025-11-06 09:24:27 +6 2025-11-06 09:24:27 +DROP TABLE t1, t2; +# End of 11.4 tests diff --git a/mysql-test/main/having.test b/mysql-test/main/having.test index 4b00334d2c4..e2c363fb48b 100644 --- a/mysql-test/main/having.test +++ b/mysql-test/main/having.test @@ -1078,3 +1078,28 @@ SET optimizer_trace= @save_optimizer_trace; --echo # --echo # End of 10.11 tests --echo # + +--echo # +--echo # MDEV-38070 wrong resultset with having and or condition +--echo # + +CREATE TABLE t1 ( a int, PRIMARY KEY (a)) ; +INSERT INTO t1 values (3),(4),(5),(6),(7); + +CREATE TABLE t2 (b int , c TIMESTAMP ); +INSERT INTO t2 VALUES (1,'2025-11-06 09:24:27'),(1,'2025-11-06 09:24:27'), +(2,'2025-11-06 09:24:27'),(2,'2025-11-06 09:24:27'),(3,'2025-11-06 09:24:27'), +(3,'2025-11-06 09:24:27'),(4,'2025-11-06 09:24:27'),(4,'2025-11-06 09:24:27'), +(5,'2025-11-06 09:24:27'),(5,'2025-11-06 09:24:27'),(6,'2025-11-06 09:24:27'), +(6,'2025-11-06 09:24:27'),(7,'2025-11-06 11:24:27'),(7,'2025-11-06 11:24:27'); + +SELECT t1.a, tbl.b + FROM t1 + JOIN ( SELECT t2.b as id2, max(t2.c) AS b FROM t2 GROUP BY t2.b ) tbl + ON tbl.id2 = t1.a + GROUP BY t1.a + HAVING (tbl.b < '2025-11-06 10:40:00'); + +DROP TABLE t1, t2; + +--echo # End of 11.4 tests diff --git a/mysql-test/main/limit_rows_examined.result b/mysql-test/main/limit_rows_examined.result index 0ced7eeb089..4dcb3afc4c2 100644 --- a/mysql-test/main/limit_rows_examined.result +++ b/mysql-test/main/limit_rows_examined.result @@ -942,3 +942,17 @@ LIMIT ROWS EXAMINED 1; 1 DROP TABLE t1; # End of 10.11 tests +# +# MDEV-38683 SIGSEGV (dbg), SIGABRT or ER_EMPTY_QUERY when using +# ROWS EXAMINED with log_output=TABLE +# +SET GLOBAL general_log=ON, GLOBAL log_output='TABLE'; +CREATE TABLE t1 (c INT); +EXPLAIN SELECT * FROM t1 LIMIT ROWS EXAMINED 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 Const row not found +select 1; +1 +1 +drop table t1; +SET GLOBAL log_output= default; diff --git a/mysql-test/main/limit_rows_examined.test b/mysql-test/main/limit_rows_examined.test index 2fe7ef24fe8..65df4313640 100644 --- a/mysql-test/main/limit_rows_examined.test +++ b/mysql-test/main/limit_rows_examined.test @@ -673,3 +673,15 @@ LIMIT ROWS EXAMINED 1; DROP TABLE t1; --echo # End of 10.11 tests + +--echo # +--echo # MDEV-38683 SIGSEGV (dbg), SIGABRT or ER_EMPTY_QUERY when using +--echo # ROWS EXAMINED with log_output=TABLE +--echo # + +SET GLOBAL general_log=ON, GLOBAL log_output='TABLE'; +CREATE TABLE t1 (c INT); +EXPLAIN SELECT * FROM t1 LIMIT ROWS EXAMINED 1; +select 1; +drop table t1; +SET GLOBAL log_output= default; diff --git a/mysql-test/main/mdev-33070.cnf b/mysql-test/main/mdev-33070.cnf new file mode 100644 index 00000000000..1c6cbae760d --- /dev/null +++ b/mysql-test/main/mdev-33070.cnf @@ -0,0 +1,7 @@ +!include include/default_my.cnf + +[mysqld.1] +extra-port= @ENV.MASTER_EXTRA_PORT + +[ENV] +MASTER_EXTRA_PORT= @OPT.port diff --git a/mysql-test/main/mdev-33070.opt b/mysql-test/main/mdev-33070.opt new file mode 100644 index 00000000000..0167dad7826 --- /dev/null +++ b/mysql-test/main/mdev-33070.opt @@ -0,0 +1 @@ +--thread-handling=pool-of-threads --loose-thread-pool-mode=generic --thread-pool-size=1 --thread-pool-max-threads=3 --thread-pool-oversubscribe=1 --thread-pool-stall-limit=10000 --thread-pool-dedicated-listener diff --git a/mysql-test/main/mdev-33070.result b/mysql-test/main/mdev-33070.result new file mode 100644 index 00000000000..2c6ebdc8407 --- /dev/null +++ b/mysql-test/main/mdev-33070.result @@ -0,0 +1,35 @@ +# MDEV-33070 Thread pool starvation at oversubscribe threshold +CREATE TABLE t1 (a INT); +connect c1, localhost, root,,; +connect c2, localhost, root,,; +connect c3, localhost, root,,; +connect extra_con, 127.0.0.1, root,,test,$MASTER_EXTRA_PORT,; +connection c1; +SELECT SLEEP(1000); +connection extra_con; +connection c2; +SELECT SLEEP(1000); +connection extra_con; +connection c3; +INSERT INTO t1 VALUES (1); +connection extra_con; +KILL QUERY c1_id; +SELECT COUNT(*) = 1 FROM t1; +COUNT(*) = 1 +1 +connection c1; +disconnect c1; +connection extra_con; +KILL QUERY c2_id; +connection c2; +disconnect c2; +connection c3; +disconnect c3; +connection extra_con; +SELECT COUNT(*) = 1 FROM t1; +COUNT(*) = 1 +1 +disconnect extra_con; +connection default; +DROP TABLE t1; +# End of MDEV-33070 tests diff --git a/mysql-test/main/mdev-33070.test b/mysql-test/main/mdev-33070.test new file mode 100644 index 00000000000..f74ed71b1f8 --- /dev/null +++ b/mysql-test/main/mdev-33070.test @@ -0,0 +1,83 @@ +--source include/not_embedded.inc +--source include/have_pool_of_threads.inc + +--echo # MDEV-33070 Thread pool starvation at oversubscribe threshold + +# The server is started with a single thread group, a dedicated listener, +# one worker thread, and thread_pool_oversubscribe=1. +# +# c1 and c2 run long queries and occupy the one worker plus the one allowed +# oversubscribe slot. c3 submits a trivial INSERT which the listener can only +# enqueue, because it is sent only after both c1 and c2 are confirmed running. +# +# Before the fix, after c1 was killed the worker stayed at the oversubscribe +# threshold and went to sleep instead of dequeuing c3. Because +# thread_pool_dedicated_listener=ON, only the worker can drain the queue, so if +# c3 is still pending while c1 and c2 run and completes only after c1 is +# killed, then the worker resumed dequeuing. + +CREATE TABLE t1 (a INT); + +--connect (c1, localhost, root,,) +--connect (c2, localhost, root,,) +--connect (c3, localhost, root,,) +--connect (extra_con, 127.0.0.1, root,,test,$MASTER_EXTRA_PORT,) + +--connection c1 +--let $c1_id= `SELECT CONNECTION_ID()` +--send SELECT SLEEP(1000) + +--connection extra_con +let $wait_condition= + SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE='User sleep' AND ID=$c1_id; +--source include/wait_condition.inc + +--connection c2 +--let $c2_id= `SELECT CONNECTION_ID()` +--send SELECT SLEEP(1000) + +--connection extra_con +let $wait_condition= + SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.PROCESSLIST + WHERE STATE='User sleep' AND ID=$c2_id; +--source include/wait_condition.inc + +--connection c3 +--send INSERT INTO t1 VALUES (1) + +--connection extra_con +--replace_result $c1_id c1_id +eval KILL QUERY $c1_id; + +let $wait_timeout= 10; +let $wait_condition= + SELECT COUNT(*) = 1 FROM t1; +--source include/wait_condition.inc +SELECT COUNT(*) = 1 FROM t1; + +--connection c1 +--error 0,ER_QUERY_INTERRUPTED,ER_STATEMENT_TIMEOUT +--reap +--disconnect c1 + +--connection extra_con +--replace_result $c2_id c2_id +eval KILL QUERY $c2_id; + +--connection c2 +--error 0,ER_QUERY_INTERRUPTED +--reap +--disconnect c2 + +--connection c3 +--reap +--disconnect c3 + +--connection extra_con +SELECT COUNT(*) = 1 FROM t1; +--disconnect extra_con + +--connection default +DROP TABLE t1; +--echo # End of MDEV-33070 tests diff --git a/mysql-test/main/mdev_38998.result b/mysql-test/main/mdev_38998.result new file mode 100644 index 00000000000..9ef9b1d9ff6 --- /dev/null +++ b/mysql-test/main/mdev_38998.result @@ -0,0 +1,29 @@ +# +# MDEV-38998: Assertion failure in diagnostics area upon INSERT/UPDATE IGNORE and check with ER_DATA_OUT_OF_RANGE +# +CREATE TABLE t1 (f INT, CHECK(COT(f))); +# Test INSERT IGNORE +INSERT IGNORE INTO t1 VALUES (0); +Warnings: +Error 1690 DOUBLE value is out of range in 'cot(`test`.`t1`.`f`)' +Warning 4025 CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` +# Test several values with INSERT IGNORE +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 VALUES (0), (1); +Warnings: +Error 1690 DOUBLE value is out of range in 'cot(`test`.`t1`.`f`)' +Warning 4025 CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` +SELECT * FROM t1; +f +1 +# Test UPDATE IGNORE +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (1); +UPDATE IGNORE t1 SET f=0; +Warnings: +Error 1690 DOUBLE value is out of range in 'cot(`test`.`t1`.`f`)' +Warning 4025 CONSTRAINT `CONSTRAINT_1` failed for `test`.`t1` +SELECT * FROM t1; +f +1 +DROP TABLE t1; diff --git a/mysql-test/main/mdev_38998.test b/mysql-test/main/mdev_38998.test new file mode 100644 index 00000000000..ae943c03df2 --- /dev/null +++ b/mysql-test/main/mdev_38998.test @@ -0,0 +1,26 @@ +--source include/have_debug.inc + +--echo # +--echo # MDEV-38998: Assertion failure in diagnostics area upon INSERT/UPDATE IGNORE and check with ER_DATA_OUT_OF_RANGE +--echo # + +CREATE TABLE t1 (f INT, CHECK(COT(f))); + +--echo # Test INSERT IGNORE +INSERT IGNORE INTO t1 VALUES (0); + + +--echo # Test several values with INSERT IGNORE +TRUNCATE TABLE t1; +INSERT IGNORE INTO t1 VALUES (0), (1); + +SELECT * FROM t1; + +--echo # Test UPDATE IGNORE +TRUNCATE TABLE t1; +INSERT INTO t1 VALUES (1); +UPDATE IGNORE t1 SET f=0; + +SELECT * FROM t1; + +DROP TABLE t1; diff --git a/mysql-test/main/mysql-interactive.result b/mysql-test/main/mysql-interactive.result index cd083339ace..e73b8618c78 100644 --- a/mysql-test/main/mysql-interactive.result +++ b/mysql-test/main/mysql-interactive.result @@ -66,3 +66,70 @@ Query OK, 0 rows affected MariaDB [(none)]> exit Bye # End of 10.11 tests +# +# MDEV-38922 CLI incorrectly adds "stage done" on REPAIR TABLE output +# +CREATE TABLE t (c INT) ENGINE=InnoDB; +REPAIR TABLE t; +DROP TABLE t; +exit +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MariaDB connection id is X +Server version: Y +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Help others discover MariaDB. Star it on GitHub: https://github.com/MariaDB/server + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +MariaDB [test]> CREATE TABLE t (c INT) ENGINE=InnoDB; +Query OK, 0 rows affected + +MariaDB [test]> REPAIR TABLE t; +Stage: X of Y 'Z' P% of stage done +--------+--------+----------+----------+ +| Table | Op | Msg_type | Msg_text | ++--------+--------+----------+----------+ +| test.t | repair | status | OK | ++--------+--------+----------+----------+ +1 row in set + +MariaDB [test]> DROP TABLE t; +Query OK, 0 rows affected + +MariaDB [test]> exit +Bye +# +# repair table output in unbuffered (--quick) mode +# +CREATE TABLE t (c INT) ENGINE=InnoDB; +INSERT INTO t SELECT * FROM seq_1_to_10; +REPAIR TABLE t; +DROP TABLE t; +exit +Welcome to the MariaDB monitor. Commands end with ; or \g. +Your MariaDB connection id is X +Server version: Y +Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. + +Help others discover MariaDB. Star it on GitHub: https://github.com/MariaDB/server + +Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. + +MariaDB [test]> CREATE TABLE t (c INT) ENGINE=InnoDB; +Query OK, 0 rows affected + +MariaDB [test]> INSERT INTO t SELECT * FROM seq_1_to_10; +MariaDB [test]> REPAIR TABLE t; ++--------+--------+----------+----------+ +| Table | Op | Msg_type | Msg_text | ++--------+--------+----------+----------+ +Stage: X of Y 'Z' P% of stage done | test.t | repair | status | OK | ++--------+--------+----------+----------+ +1 row in set + +MariaDB [test]> DROP TABLE t; +Query OK, 0 rows affected + +MariaDB [test]> exit +Bye +# End of 11.8 tests diff --git a/mysql-test/main/mysql-interactive.test b/mysql-test/main/mysql-interactive.test index 1c8fc6010f7..f56adfb2b25 100644 --- a/mysql-test/main/mysql-interactive.test +++ b/mysql-test/main/mysql-interactive.test @@ -1,10 +1,11 @@ +# this would need an instrumented ncurses library +source include/not_msan.inc; +source include/not_embedded.inc; +source include/not_windows.inc; +source include/have_innodb.inc; --echo # --echo # regression introduced by MDEV-14448 --echo # -source include/not_embedded.inc; -source include/not_windows.inc; -# this would need an instrumented ncurses library -source include/not_msan.inc; write_file $MYSQL_TMP_DIR/mysql_in; delimiter $ @@ -46,3 +47,46 @@ exec socat -t10 EXEC:"$MYSQL",pty STDIO < $MYSQL_TMP_DIR/mysql_in; remove_file $MYSQL_TMP_DIR/mysql_in; --echo # End of 10.11 tests + +--echo # +--echo # MDEV-38922 CLI incorrectly adds "stage done" on REPAIR TABLE output +--echo # +write_file $MYSQL_TMP_DIR/mysql_in; +CREATE TABLE t (c INT) ENGINE=InnoDB; +REPAIR TABLE t; +DROP TABLE t; +exit +EOF +let TERM=dumb; +replace_regex /id is \d+/id is X/ /Server version: .*/Server version: Y/ / \(\d+\.\d+ sec\)// /Stage: \d+ of \d+ '.*?'\s+[0-9.]+% of stage done/Stage: X of Y 'Z' P% of stage done/ / +\r//; +error 0,127; +exec socat -t30 EXEC:"$MYSQL test",pty STDIO < $MYSQL_TMP_DIR/mysql_in; +if ($sys_errno == 127) +{ + remove_file $MYSQL_TMP_DIR/mysql_in; + skip no socat; +} +remove_file $MYSQL_TMP_DIR/mysql_in; + +--echo # +--echo # repair table output in unbuffered (--quick) mode +--echo # +write_file $MYSQL_TMP_DIR/mysql_in; +CREATE TABLE t (c INT) ENGINE=InnoDB; +INSERT INTO t SELECT * FROM seq_1_to_10; +REPAIR TABLE t; +DROP TABLE t; +exit +EOF +let TERM=dumb; +replace_regex /id is \d+/id is X/ /Server version: .*/Server version: Y/ / \(\d+\.\d+ sec\)// /Stage: \d+ of \d+ '.*?'\s+[0-9.]+% of stage done/Stage: X of Y 'Z' P% of stage done/ / +\r//; +error 0,127; +exec socat -t30 EXEC:"$MYSQL test -q --quick-max-column-width 6",pty STDIO < $MYSQL_TMP_DIR/mysql_in; +if ($sys_errno == 127) +{ + remove_file $MYSQL_TMP_DIR/mysql_in; + skip no socat; +} +remove_file $MYSQL_TMP_DIR/mysql_in; + +--echo # End of 11.8 tests diff --git a/mysql-test/main/mysql_upgrade.result b/mysql-test/main/mysql_upgrade.result index 8903dcf7a7b..3d3c16b1d98 100644 --- a/mysql-test/main/mysql_upgrade.result +++ b/mysql-test/main/mysql_upgrade.result @@ -2455,3 +2455,18 @@ GRANT USAGE ON *.* TO `foo`@`bar` GRANT ALL PRIVILEGES ON `mysql`.* TO `foo`@`bar` drop user foo@bar; # End of 11.3 tests +# +# MDEV-38698 mysql_upgrade does not fix charset and collation for mysql.user +# +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SELECT CHARACTER_SET_CLIENT, COLLATION_CONNECTION FROM INFORMATION_SCHEMA.VIEWS +WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'; +CHARACTER_SET_CLIENT COLLATION_CONNECTION +utf8mb3 utf8mb3_general_ci +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SELECT CHARACTER_SET_CLIENT, COLLATION_CONNECTION FROM INFORMATION_SCHEMA.VIEWS +WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'; +CHARACTER_SET_CLIENT COLLATION_CONNECTION +latin1 latin1_swedish_ci diff --git a/mysql-test/main/mysql_upgrade.test b/mysql-test/main/mysql_upgrade.test index 463a6c94cd1..87947d63875 100644 --- a/mysql-test/main/mysql_upgrade.test +++ b/mysql-test/main/mysql_upgrade.test @@ -577,3 +577,25 @@ show grants for foo@bar; drop user foo@bar; --echo # End of 11.3 tests + + +--echo # +--echo # MDEV-38698 mysql_upgrade does not fix charset and collation for mysql.user +--echo # + +--remove_file $MYSQLD_DATADIR/mysql/user.frm +--copy_file std_data/upgrade/user-100625-utf8mb3.frm $MYSQLD_DATADIR/mysql/user.frm + +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SELECT CHARACTER_SET_CLIENT, COLLATION_CONNECTION FROM INFORMATION_SCHEMA.VIEWS +WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'; + +--replace_result $MYSQLTEST_VARDIR var +--exec $MYSQL_UPGRADE --force --silent 2>&1 +--remove_file $MYSQLD_DATADIR/mariadb_upgrade_info + +FLUSH TABLES mysql.user; +FLUSH PRIVILEGES; +SELECT CHARACTER_SET_CLIENT, COLLATION_CONNECTION FROM INFORMATION_SCHEMA.VIEWS +WHERE TABLE_SCHEMA='mysql' AND TABLE_NAME='user'; diff --git a/mysql-test/main/mysqlcheck.result b/mysql-test/main/mysqlcheck.result index 68b95abced8..f82a96a980d 100644 --- a/mysql-test/main/mysqlcheck.result +++ b/mysql-test/main/mysqlcheck.result @@ -494,3 +494,11 @@ select db_name,table_name,column_name,min_value,max_value,nulls_ratio,avg_length db_name table_name column_name min_value max_value nulls_ratio avg_length avg_frequency test t1 a 1 3 0.0000 4.0000 1.0000 drop table t1; +# +# MDEV-38778 mariadbcheck --silent +# +create table t1 (a int) engine=innodb; +test.t1 +note : Table does not support optimize, doing recreate + analyze instead +drop table t1; +# End of 10.11 tests diff --git a/mysql-test/main/mysqlcheck.test b/mysql-test/main/mysqlcheck.test index a9d263456fb..ec815ce2b50 100644 --- a/mysql-test/main/mysqlcheck.test +++ b/mysql-test/main/mysqlcheck.test @@ -422,3 +422,12 @@ select db_name,table_name,column_name,min_value,max_value,nulls_ratio,avg_length --exec $MYSQL_CHECK --analyze test t1 --persistent select db_name,table_name,column_name,min_value,max_value,nulls_ratio,avg_length,avg_frequency from mysql.column_stats where db_name = 'test' and table_name = 't1' order by db_name,table_name; drop table t1; + +--echo # +--echo # MDEV-38778 mariadbcheck --silent +--echo # +create table t1 (a int) engine=innodb; +--exec $MYSQL_CHECK -s --optimize test t1 +drop table t1; + +--echo # End of 10.11 tests diff --git a/mysql-test/main/mysqltest.result b/mysql-test/main/mysqltest.result index 7bbe7d9a6d0..8daf4b17d32 100644 --- a/mysql-test/main/mysqltest.result +++ b/mysql-test/main/mysqltest.result @@ -1002,4 +1002,9 @@ SELECT 1 /* doesn't throw error */; SELECT 1 /* doesn't throw error */; 1 1 -# End of tests +# +# MDEV-38696: infinite loop in my_copy() function +# +# caught error and exited my_copy() +# End of 10.11 tests +End of tests diff --git a/mysql-test/main/mysqltest.test b/mysql-test/main/mysqltest.test index 3db8e363170..db8050ee03f 100644 --- a/mysql-test/main/mysqltest.test +++ b/mysql-test/main/mysqltest.test @@ -17,6 +17,9 @@ echo $mysql_errname before test; # This test uses chmod, can't be run with root permissions --source include/not_as_root.inc +# Save the initial number of concurrent sessions +--source include/count_sessions.inc + # Some tests below connect/disconnect rapidly in a loop. This causes a race # where mysqld may not have time to register the previous disconnects before # new connects, and eventually we run out of connections. So we need to @@ -2957,7 +2960,27 @@ set sql_mode=default; SELECT 1 /* doesn't throw error */; SELECT 1 /* doesn't throw error */; ---echo # End of tests +--echo # +--echo # MDEV-38696: infinite loop in my_copy() function +--echo # + +--let $srcdir= $MYSQLTEST_VARDIR/tmp/mdev_38696_srcdir +--let $dstfile= $MYSQLTEST_VARDIR/tmp/mdev_38696_dstfile + +--mkdir $srcdir + +--error 1 +--copy_file $srcdir $dstfile +--echo # caught error and exited my_copy() + +--rmdir $srcdir + +--echo # End of 10.11 tests + +--echo End of tests + +# Wait till we reached the initial number of concurrent sessions +--source include/wait_until_count_sessions.inc --disable_query_log --eval SET GLOBAL max_connections = $saved_max_connections diff --git a/mysql-test/main/mysqltest_string_functions.result b/mysql-test/main/mysqltest_string_functions.result index e6f848cef6f..eb3d56e6554 100644 --- a/mysql-test/main/mysqltest_string_functions.result +++ b/mysql-test/main/mysqltest_string_functions.result @@ -2,6 +2,32 @@ # Test for MDEV-36108: Variable substitutions in mysqltest # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- +# Test absolute value function +# ---------------------------------------------------------------------------- +# Basic abs() function tests +abs(10) -> 10; +abs(-10) -> 10; +abs(0) -> 0; +abs(123456789) -> 123456789; +abs(-987654321) -> 987654321; +abs(NULL) -> ; +abs(5 - 10) -> 5; +abs(10 - 5) -> 5; +abs(-(-25)) -> 25; +abs(-2147483648) -> 2147483648; +abs(2147483647) -> 2147483647; +abs(1 == 1) -> 1; +abs(1 == 0) -> 0; +abs(-((5 * -3) + (2 - 8))) -> 21; +abs(((10 - 25) * (3 + 2))) -> 75; +abs(((2 - 6) * (-4 + 1))) -> 12; +abs((((-5 * 6) + 10) - (8 * -2))) -> 4; +abs(((((3 - 9) * 2) + 4) - 1)) -> 9; +abs(((-100 + 50) * (2 - 5))) -> 150; +abs(((-3 * (2 + 4)) + (18 / 3))) -> 12; +abs(((((10 - 5) * -3) + 4) * -2)) -> 22; +abs((((-2 * -2) - (5 * 3)) + 20)) -> 9; +# ---------------------------------------------------------------------------- # Test conversion functions (conv, bin, oct, hex) # ---------------------------------------------------------------------------- # Basic conv() function tests diff --git a/mysql-test/main/mysqltest_string_functions.test b/mysql-test/main/mysqltest_string_functions.test index 9115e46923d..10e0d546e15 100644 --- a/mysql-test/main/mysqltest_string_functions.test +++ b/mysql-test/main/mysqltest_string_functions.test @@ -4,6 +4,79 @@ --source include/not_embedded.inc +--echo # ---------------------------------------------------------------------------- +--echo # Test absolute value function +--echo # ---------------------------------------------------------------------------- + +--echo # Basic abs() function tests + +let $a1 = $(abs(10)); +-- echo abs(10) -> $a1; + +let $a2 = $(abs(-10)); +-- echo abs(-10) -> $a2; + +let $a3 = $(abs(0)); +-- echo abs(0) -> $a3; + +let $a4 = $(abs(123456789)); +-- echo abs(123456789) -> $a4; + +let $a5 = $(abs(-987654321)); +-- echo abs(-987654321) -> $a5; + +let $a6 = $(abs(NULL)); +-- echo abs(NULL) -> $a6; + +let $a7 = $(abs(5 - 10)); +-- echo abs(5 - 10) -> $a7; + +let $a8 = $(abs(10 - 5)); +-- echo abs(10 - 5) -> $a8; + +let $a9 = $(abs(-(-25))); +-- echo abs(-(-25)) -> $a9; + +let $a10 = $(abs(-2147483648)); +-- echo abs(-2147483648) -> $a10; + +let $a11 = $(abs(2147483647)); +-- echo abs(2147483647) -> $a11; + +let $a12 = $(abs(1 == 1)); +-- echo abs(1 == 1) -> $a12; + +let $a13 = $(abs(1 == 0)); +-- echo abs(1 == 0) -> $a13; + +let $a14 = $(abs(-((5 * -3) + (2 - 8)))); +-- echo abs(-((5 * -3) + (2 - 8))) -> $a14; + +let $a15 = $(abs(((10 - 25) * (3 + 2)))); +-- echo abs(((10 - 25) * (3 + 2))) -> $a15; + +let $a16 = $(abs(((2 - 6) * (-4 + 1)))); +-- echo abs(((2 - 6) * (-4 + 1))) -> $a16; + +let $a17 = $(abs((((-5 * 6) + 10) - (8 * -2)))); +-- echo abs((((-5 * 6) + 10) - (8 * -2))) -> $a17; + +let $a18 = $(abs(((((3 - 9) * 2) + 4) - 1))); +-- echo abs(((((3 - 9) * 2) + 4) - 1)) -> $a18; + +let $a19 = $(abs(((-100 + 50) * (2 - 5)))); +-- echo abs(((-100 + 50) * (2 - 5))) -> $a19; + +let $a20 = $(abs(((-3 * (2 + 4)) + (18 / 3)))); +-- echo abs(((-3 * (2 + 4)) + (18 / 3))) -> $a20; + +let $a21 = $(abs(((((10 - 5) * -3) + 4) * -2))); +-- echo abs(((((10 - 5) * -3) + 4) * -2)) -> $a21; + +let $a22 = $(abs((((-2 * -2) - (5 * 3)) + 20))); +-- echo abs((((-2 * -2) - (5 * 3)) + 20)) -> $a22; + + --echo # ---------------------------------------------------------------------------- --echo # Test conversion functions (conv, bin, oct, hex) --echo # ---------------------------------------------------------------------------- diff --git a/mysql-test/main/set_operation_oracle.result b/mysql-test/main/set_operation_oracle.result index 95cc7dda806..37582afc4d9 100644 --- a/mysql-test/main/set_operation_oracle.result +++ b/mysql-test/main/set_operation_oracle.result @@ -147,3 +147,72 @@ set SQL_MODE=oracle; select * from t13 union select * from t234 intersect all select * from t12; ERROR 42S02: Table 'test.t13' doesn't exist set SQL_MODE=default; +# +# MDEV-38799 Some views are broken in Oracle mode after upgrade to Q1 2026 +# +set sql_mode=''; +create view v as select 'foo' as a union select 'bar' as a; +create view v2 as select 'foo' as a, 'baz' as b union select 'bar' as a, 'qux' as b; +create view v3 as select * from (select 'foo' as a, 'baz' as b) s union select * from (select 'bar' as a, 'qux' as b) s2; +create view v4 as select * from (select 'foo' as a) s union select * from (select 'bar' as a) s2; +select a from v; +a +foo +bar +select a, b from v2; +a b +foo baz +bar qux +select a, b from v3; +a b +foo baz +bar qux +select a from v4; +a +foo +bar +set sql_mode=oracle; +show create view v; +View Create View character_set_client collation_connection +v CREATE VIEW "v" AS select "__4"."a" AS "a" from (select 'foo' AS "a" union select 'bar' AS "a") "__4" latin1 latin1_swedish_ci +show create view v2; +View Create View character_set_client collation_connection +v2 CREATE VIEW "v2" AS select "__4"."a" AS "a","__4"."b" AS "b" from (select 'foo' AS "a",'baz' AS "b" union select 'bar' AS "a",'qux' AS "b") "__4" latin1 latin1_swedish_ci +select a from v; +a +foo +bar +select a, b from v2; +a b +foo baz +bar qux +select a, b from v3; +a b +foo baz +bar qux +select a from v4; +a +foo +bar +drop view v; +drop view v2; +drop view v3; +drop view v4; +set sql_mode=default; +# End of 10.11 tests +# +# MDEV-38987 ASAN heap-use-after-free upon using a view through a trigger in ORACLE mode +# +set sql_mode = oracle; +create table t1 (f int); +create table t2 (a int); +create view v as select 'x' union select 'x' union select 'x'; +create trigger tr before insert on t1 for each row delete from v; +insert into t1 values (1); +ERROR HY000: The target table v of the DELETE is not updatable +drop view v; +create view v as select * from t2; +INSERT into t1 values (2); +drop view v; +drop table t1, t2; +# End of 11.4 tests diff --git a/mysql-test/main/set_operation_oracle.test b/mysql-test/main/set_operation_oracle.test index 52152b83110..d012d244d21 100644 --- a/mysql-test/main/set_operation_oracle.test +++ b/mysql-test/main/set_operation_oracle.test @@ -74,3 +74,50 @@ set SQL_MODE=oracle; --error ER_NO_SUCH_TABLE select * from t13 union select * from t234 intersect all select * from t12; set SQL_MODE=default; + +--echo # +--echo # MDEV-38799 Some views are broken in Oracle mode after upgrade to Q1 2026 +--echo # +set sql_mode=''; +create view v as select 'foo' as a union select 'bar' as a; +create view v2 as select 'foo' as a, 'baz' as b union select 'bar' as a, 'qux' as b; +create view v3 as select * from (select 'foo' as a, 'baz' as b) s union select * from (select 'bar' as a, 'qux' as b) s2; +create view v4 as select * from (select 'foo' as a) s union select * from (select 'bar' as a) s2; +select a from v; +select a, b from v2; +select a, b from v3; +select a from v4; +set sql_mode=oracle; +show create view v; +show create view v2; +select a from v; +select a, b from v2; +select a, b from v3; +select a from v4; +drop view v; +drop view v2; +drop view v3; +drop view v4; +set sql_mode=default; + +--echo # End of 10.11 tests + +--echo # +--echo # MDEV-38987 ASAN heap-use-after-free upon using a view through a trigger in ORACLE mode +--echo # +set sql_mode = oracle; + +create table t1 (f int); +create table t2 (a int); +create view v as select 'x' union select 'x' union select 'x'; +create trigger tr before insert on t1 for each row delete from v; +--error ER_NON_UPDATABLE_TABLE +insert into t1 values (1); +drop view v; +create view v as select * from t2; +INSERT into t1 values (2); + +drop view v; +drop table t1, t2; + +--echo # End of 11.4 tests diff --git a/mysql-test/main/skip_grants.result b/mysql-test/main/skip_grants.result index b22f1545e81..569e4f64ea3 100644 --- a/mysql-test/main/skip_grants.result +++ b/mysql-test/main/skip_grants.result @@ -148,6 +148,47 @@ EXPECT_0 # restart: --skip-grant-tables # End of 10.10 tests # +# MDEV-38811 crash in information_schema.table_constraints when --skip-grant-tables +# +select * from information_schema.table_constraints; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_SCHEMA TABLE_NAME CONSTRAINT_TYPE +def mysql Host mysql roles_mapping UNIQUE +def mysql Options mysql servers CHECK +def mysql PRIMARY mysql column_stats PRIMARY KEY +def mysql PRIMARY mysql columns_priv PRIMARY KEY +def mysql PRIMARY mysql db PRIMARY KEY +def mysql PRIMARY mysql event PRIMARY KEY +def mysql PRIMARY mysql func PRIMARY KEY +def mysql PRIMARY mysql global_priv PRIMARY KEY +def mysql PRIMARY mysql gtid_slave_pos PRIMARY KEY +def mysql PRIMARY mysql help_category PRIMARY KEY +def mysql PRIMARY mysql help_keyword PRIMARY KEY +def mysql PRIMARY mysql help_relation PRIMARY KEY +def mysql PRIMARY mysql help_topic PRIMARY KEY +def mysql PRIMARY mysql index_stats PRIMARY KEY +def mysql PRIMARY mysql plugin PRIMARY KEY +def mysql PRIMARY mysql proc PRIMARY KEY +def mysql PRIMARY mysql procs_priv PRIMARY KEY +def mysql PRIMARY mysql proxies_priv PRIMARY KEY +def mysql PRIMARY mysql servers PRIMARY KEY +def mysql PRIMARY mysql table_stats PRIMARY KEY +def mysql PRIMARY mysql tables_priv PRIMARY KEY +def mysql PRIMARY mysql time_zone PRIMARY KEY +def mysql PRIMARY mysql time_zone_leap_second PRIMARY KEY +def mysql PRIMARY mysql time_zone_name PRIMARY KEY +def mysql PRIMARY mysql time_zone_transition PRIMARY KEY +def mysql PRIMARY mysql time_zone_transition_type PRIMARY KEY +def mysql Priv mysql global_priv CHECK +def mysql name mysql help_category UNIQUE +def mysql name mysql help_keyword UNIQUE +def mysql name mysql help_topic UNIQUE +def sys PRIMARY sys sys_config PRIMARY KEY +Warnings: +Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' +Warning 1286 Unknown storage engine 'InnoDB' +# End of 10.11 tests +# # MDEV-36351 MariaDB crashes when trying to access information_schema.users under --skip-grant-tables # select * from information_schema.users; diff --git a/mysql-test/main/skip_grants.test b/mysql-test/main/skip_grants.test index a21e5c74d3e..65c3d88b60a 100644 --- a/mysql-test/main/skip_grants.test +++ b/mysql-test/main/skip_grants.test @@ -186,6 +186,14 @@ SELECT @@skip_grant_tables AS EXPECT_0; --echo # End of 10.10 tests +--echo # +--echo # MDEV-38811 crash in information_schema.table_constraints when --skip-grant-tables +--echo # +--sorted_result +select * from information_schema.table_constraints; + +--echo # End of 10.11 tests + --echo # --echo # MDEV-36351 MariaDB crashes when trying to access information_schema.users under --skip-grant-tables --echo # diff --git a/mysql-test/main/sp-error.result b/mysql-test/main/sp-error.result index 241e62d8a3b..430a7e33958 100644 --- a/mysql-test/main/sp-error.result +++ b/mysql-test/main/sp-error.result @@ -1571,7 +1571,12 @@ declare continue handler for 0 set @x=0; end$$ ERROR HY000: Incorrect CONDITION value: '0' set @old_recursion_depth = @@max_sp_recursion_depth; -set @@max_sp_recursion_depth = 255; +set @l = 255; +SELECT IF(global_value like 'MSAN%', 20, +IF(global_value LIKE 'ASAN%', 200, 255)) INTO @l +FROM information_schema.system_variables +WHERE variable_name='have_sanitizer' AND version() LIKE '%debug%'; +set @@max_sp_recursion_depth = @l; create procedure p1(a int) begin declare continue handler for 1436 -- ER_STACK_OVERRUN_NEED_MORE diff --git a/mysql-test/main/sp-error.test b/mysql-test/main/sp-error.test index 675fa763729..6d0c4364aa9 100644 --- a/mysql-test/main/sp-error.test +++ b/mysql-test/main/sp-error.test @@ -2230,10 +2230,17 @@ delimiter ;$$ # # Bug#15192: "fatal errors" are caught by handlers in stored procedures -# +# MDEV-39109 - lower limits for debug sanitizers. set @old_recursion_depth = @@max_sp_recursion_depth; -set @@max_sp_recursion_depth = 255; +set @l = 255; +--disable_warnings +SELECT IF(global_value like 'MSAN%', 20, + IF(global_value LIKE 'ASAN%', 200, 255)) INTO @l + FROM information_schema.system_variables + WHERE variable_name='have_sanitizer' AND version() LIKE '%debug%'; +--enable_warnings +set @@max_sp_recursion_depth = @l; delimiter |; create procedure p1(a int) begin diff --git a/mysql-test/main/temp_table.result b/mysql-test/main/temp_table.result index e3743f467d1..75f9cd1eed6 100644 --- a/mysql-test/main/temp_table.result +++ b/mysql-test/main/temp_table.result @@ -699,6 +699,27 @@ UNLOCK TABLES; DROP TABLE t1; # End of 10.6 tests # +# Failed CREATE TEMPORARY ... SELECT must not roll back transaction +# +CREATE TABLE t (pk INT PRIMARY KEY) ENGINE=InnoDB; +START TRANSACTION; +INSERT INTO t VALUES (0); +INSERT INTO t VALUES (1); +CREATE TEMPORARY TABLE tmp2 (a INT) ENGINE=InnoDB SELECT 'x' AS a; +ERROR 22007: Incorrect integer value: 'x' for column `test`.`tmp2`.`a` at row 1 +SELECT * FROM t ORDER BY pk; +pk +0 +1 +INSERT INTO t VALUES (1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +COMMIT; +SELECT * FROM t ORDER BY pk; +pk +0 +1 +DROP TABLE t; +# # MDEV-38716: Server crashes in TABLE::evaluate_update_default_function # # Test case where ALTER doesn't add any new columns with default values diff --git a/mysql-test/main/temp_table.test b/mysql-test/main/temp_table.test index f5f6dcd726e..ea6201c45ab 100644 --- a/mysql-test/main/temp_table.test +++ b/mysql-test/main/temp_table.test @@ -767,6 +767,23 @@ DROP TABLE t1; --echo # End of 10.6 tests +--echo # +--echo # Failed CREATE TEMPORARY ... SELECT must not roll back transaction +--echo # + +CREATE TABLE t (pk INT PRIMARY KEY) ENGINE=InnoDB; +START TRANSACTION; +INSERT INTO t VALUES (0); +INSERT INTO t VALUES (1); +--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD +CREATE TEMPORARY TABLE tmp2 (a INT) ENGINE=InnoDB SELECT 'x' AS a; +SELECT * FROM t ORDER BY pk; +--error ER_DUP_ENTRY +INSERT INTO t VALUES (1); +COMMIT; +SELECT * FROM t ORDER BY pk; +DROP TABLE t; + --echo # --echo # MDEV-38716: Server crashes in TABLE::evaluate_update_default_function --echo # diff --git a/mysql-test/main/vector_funcs.result b/mysql-test/main/vector_funcs.result index 171bb6c7433..6aba9df0b05 100644 --- a/mysql-test/main/vector_funcs.result +++ b/mysql-test/main/vector_funcs.result @@ -265,4 +265,14 @@ drop table t; # select vec_distance(value(key_cache_name), 0x30303030) from information_schema.key_caches; ERROR HY000: Cannot determine distance type for VEC_DISTANCE, index is not found +# +# MDEV-35211: VEC_FromText does not return vector type but varbinary +# +create table t as select vec_fromtext('[1,2,3]') as v; +show create table t; +Table Create Table +t CREATE TABLE `t` ( + `v` vector(3) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +drop table t; # End of 11.8 tests diff --git a/mysql-test/main/vector_funcs.test b/mysql-test/main/vector_funcs.test index 54f931d706e..b0ada0fa61f 100644 --- a/mysql-test/main/vector_funcs.test +++ b/mysql-test/main/vector_funcs.test @@ -153,4 +153,11 @@ drop table t; --error ER_VEC_DISTANCE_TYPE select vec_distance(value(key_cache_name), 0x30303030) from information_schema.key_caches; +--echo # +--echo # MDEV-35211: VEC_FromText does not return vector type but varbinary +--echo # +create table t as select vec_fromtext('[1,2,3]') as v; +show create table t; +drop table t; + --echo # End of 11.8 tests diff --git a/mysql-test/main/vector_innodb.result b/mysql-test/main/vector_innodb.result index 5a20d3f4c54..0b82acc3ea1 100644 --- a/mysql-test/main/vector_innodb.result +++ b/mysql-test/main/vector_innodb.result @@ -375,4 +375,16 @@ Warning 4078 Cannot cast 'int' as 'vector' in assignment of `test`.`t1`.`v` Warning 1292 Incorrect vector value: '1' for column `test`.`t1`.`v` at row 1 drop table t1; set sql_mode=default; +# +# MDEV-38349 Fix assert thd->abort_on_warning == 0 in mysql_insert +# +CREATE TABLE t1 (id INT KEY,v VECTOR (8) NOT NULL,VECTOR INDEX (v)) ENGINE=INNODB; +CREATE TABLE t2 (id INT KEY,t_id INT,INDEX par_ind (t_id),FOREIGN KEY(t_id) REFERENCES t1 (id) ON DELETE CASCADE) ENGINE=INNODB; +DROP TABLE t1; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails +INSERT INTO t1 VALUES (0,''); +ERROR 42S02: Table 'test.t1' doesn't exist in engine +DROP TABLE t2,t1; +Warnings: +Warning 1932 Table 'test.t1' doesn't exist in engine # End of 11.8 tests diff --git a/mysql-test/main/vector_innodb.test b/mysql-test/main/vector_innodb.test index efc272798f3..e083d95809f 100644 --- a/mysql-test/main/vector_innodb.test +++ b/mysql-test/main/vector_innodb.test @@ -369,4 +369,17 @@ insert t1 values (1); drop table t1; set sql_mode=default; +--echo # +--echo # MDEV-38349 Fix assert thd->abort_on_warning == 0 in mysql_insert +--echo # +CREATE TABLE t1 (id INT KEY,v VECTOR (8) NOT NULL,VECTOR INDEX (v)) ENGINE=INNODB; +CREATE TABLE t2 (id INT KEY,t_id INT,INDEX par_ind (t_id),FOREIGN KEY(t_id) REFERENCES t1 (id) ON DELETE CASCADE) ENGINE=INNODB; +--ERROR ER_ROW_IS_REFERENCED_2 +DROP TABLE t1; +--ERROR ER_NO_SUCH_TABLE_IN_ENGINE +INSERT INTO t1 VALUES (0,''); + +# cleanup +DROP TABLE t2,t1; + --echo # End of 11.8 tests diff --git a/mysql-test/std_data/upgrade/user-100625-utf8mb3.frm b/mysql-test/std_data/upgrade/user-100625-utf8mb3.frm new file mode 100644 index 00000000000..d8bf3ba3b3e --- /dev/null +++ b/mysql-test/std_data/upgrade/user-100625-utf8mb3.frm @@ -0,0 +1,16 @@ +TYPE=VIEW +query=select `mysql`.`global_priv`.`Host` AS `Host`,`mysql`.`global_priv`.`User` AS `User`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\') in (\'mysql_native_password\',\'mysql_old_password\'),ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\'),\'\') AS `Password`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1,\'Y\',\'N\') AS `Select_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2,\'Y\',\'N\') AS `Insert_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4,\'Y\',\'N\') AS `Update_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8,\'Y\',\'N\') AS `Delete_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16,\'Y\',\'N\') AS `Create_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32,\'Y\',\'N\') AS `Drop_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 64,\'Y\',\'N\') AS `Reload_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 128,\'Y\',\'N\') AS `Shutdown_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 256,\'Y\',\'N\') AS `Process_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 512,\'Y\',\'N\') AS `File_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1024,\'Y\',\'N\') AS `Grant_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2048,\'Y\',\'N\') AS `References_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4096,\'Y\',\'N\') AS `Index_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8192,\'Y\',\'N\') AS `Alter_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16384,\'Y\',\'N\') AS `Show_db_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32768,\'Y\',\'N\') AS `Super_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 65536,\'Y\',\'N\') AS `Create_tmp_table_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 131072,\'Y\',\'N\') AS `Lock_tables_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 262144,\'Y\',\'N\') AS `Execute_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 524288,\'Y\',\'N\') AS `Repl_slave_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1048576,\'Y\',\'N\') AS `Repl_client_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2097152,\'Y\',\'N\') AS `Create_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4194304,\'Y\',\'N\') AS `Show_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8388608,\'Y\',\'N\') AS `Create_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16777216,\'Y\',\'N\') AS `Alter_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 33554432,\'Y\',\'N\') AS `Create_user_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 67108864,\'Y\',\'N\') AS `Event_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 134217728,\'Y\',\'N\') AS `Trigger_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 268435456,\'Y\',\'N\') AS `Create_tablespace_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 536870912,\'Y\',\'N\') AS `Delete_history_priv`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_type\'),0) + 1,\'\',\'ANY\',\'X509\',\'SPECIFIED\') AS `ssl_type`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_cipher\'),\'\') AS `ssl_cipher`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_issuer\'),\'\') AS `x509_issuer`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_subject\'),\'\') AS `x509_subject`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_questions\'),0) as unsigned) AS `max_questions`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_updates\'),0) as unsigned) AS `max_updates`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_connections\'),0) as unsigned) AS `max_connections`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_user_connections\'),0) as signed) AS `max_user_connections`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\'),\'\') AS `plugin`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\') AS `authentication_string`,if(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.password_last_changed\'),1) = 0,\'Y\',\'N\') AS `password_expired`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.is_role\'),0) + 1,\'N\',\'Y\') AS `is_role`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.default_role\'),\'\') AS `default_role`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_statement_time\'),0.0) as decimal(12,6)) AS `max_statement_time` from `mysql`.`global_priv` +md5=9e8063501afc8396f55d7c723632d5d8 +updatable=1 +algorithm=0 +definer_user=mariadb.sys +definer_host=localhost +suid=1 +with_check_option=0 +timestamp=0001769683779044792 +create-version=2 +source=SELECT\n Host,\n User,\n IF(JSON_VALUE(Priv, \'$.plugin\') IN (\'mysql_native_password\', \'mysql_old_password\'), IFNULL(JSON_VALUE(Priv, \'$.authentication_string\'), \'\'), \'\') AS Password,\n IF(JSON_VALUE(Priv, \'$.access\') & 1, \'Y\', \'N\') AS Select_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2, \'Y\', \'N\') AS Insert_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4, \'Y\', \'N\') AS Update_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8, \'Y\', \'N\') AS Delete_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16, \'Y\', \'N\') AS Create_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 32, \'Y\', \'N\') AS Drop_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 64, \'Y\', \'N\') AS Reload_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 128, \'Y\', \'N\') AS Shutdown_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 256, \'Y\', \'N\') AS Process_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 512, \'Y\', \'N\') AS File_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 1024, \'Y\', \'N\') AS Grant_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2048, \'Y\', \'N\') AS References_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4096, \'Y\', \'N\') AS Index_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8192, \'Y\', \'N\') AS Alter_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16384, \'Y\', \'N\') AS Show_db_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 32768, \'Y\', \'N\') AS Super_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 65536, \'Y\', \'N\') AS Create_tmp_table_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 131072, \'Y\', \'N\') AS Lock_tables_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 262144, \'Y\', \'N\') AS Execute_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 524288, \'Y\', \'N\') AS Repl_slave_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 1048576, \'Y\', \'N\') AS Repl_client_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 2097152, \'Y\', \'N\') AS Create_view_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 4194304, \'Y\', \'N\') AS Show_view_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 8388608, \'Y\', \'N\') AS Create_routine_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 16777216, \'Y\', \'N\') AS Alter_routine_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 33554432, \'Y\', \'N\') AS Create_user_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 67108864, \'Y\', \'N\') AS Event_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 134217728, \'Y\', \'N\') AS Trigger_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 268435456, \'Y\', \'N\') AS Create_tablespace_priv,\n IF(JSON_VALUE(Priv, \'$.access\') & 536870912, \'Y\', \'N\') AS Delete_history_priv,\n ELT(IFNULL(JSON_VALUE(Priv, \'$.ssl_type\'), 0) + 1, \'\', \'ANY\',\'X509\', \'SPECIFIED\') AS ssl_type,\n IFNULL(JSON_VALUE(Priv, \'$.ssl_cipher\'), \'\') AS ssl_cipher,\n IFNULL(JSON_VALUE(Priv, \'$.x509_issuer\'), \'\') AS x509_issuer,\n IFNULL(JSON_VALUE(Priv, \'$.x509_subject\'), \'\') AS x509_subject,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_questions\'), 0) AS UNSIGNED) AS max_questions,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_updates\'), 0) AS UNSIGNED) AS max_updates,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_connections\'), 0) AS UNSIGNED) AS max_connections,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_user_connections\'), 0) AS SIGNED) AS max_user_connections,\n IFNULL(JSON_VALUE(Priv, \'$.plugin\'), \'\') AS plugin,\n IFNULL(JSON_VALUE(Priv, \'$.authentication_string\'), \'\') AS authentication_string,\n IF(IFNULL(JSON_VALUE(Priv, \'$.password_last_changed\'), 1) = 0, \'Y\', \'N\') AS password_expired,\n ELT(IFNULL(JSON_VALUE(Priv, \'$.is_role\'), 0) + 1, \'N\', \'Y\') AS is_role,\n IFNULL(JSON_VALUE(Priv, \'$.default_role\'), \'\') AS default_role,\n CAST(IFNULL(JSON_VALUE(Priv, \'$.max_statement_time\'), 0.0) AS DECIMAL(12,6)) AS max_statement_time\n FROM global_priv; +client_cs_name=utf8mb3 +connection_cl_name=utf8mb3_general_ci +view_body_utf8=select `mysql`.`global_priv`.`Host` AS `Host`,`mysql`.`global_priv`.`User` AS `User`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\') in (\'mysql_native_password\',\'mysql_old_password\'),ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\'),\'\') AS `Password`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1,\'Y\',\'N\') AS `Select_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2,\'Y\',\'N\') AS `Insert_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4,\'Y\',\'N\') AS `Update_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8,\'Y\',\'N\') AS `Delete_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16,\'Y\',\'N\') AS `Create_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32,\'Y\',\'N\') AS `Drop_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 64,\'Y\',\'N\') AS `Reload_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 128,\'Y\',\'N\') AS `Shutdown_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 256,\'Y\',\'N\') AS `Process_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 512,\'Y\',\'N\') AS `File_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1024,\'Y\',\'N\') AS `Grant_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2048,\'Y\',\'N\') AS `References_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4096,\'Y\',\'N\') AS `Index_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8192,\'Y\',\'N\') AS `Alter_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16384,\'Y\',\'N\') AS `Show_db_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 32768,\'Y\',\'N\') AS `Super_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 65536,\'Y\',\'N\') AS `Create_tmp_table_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 131072,\'Y\',\'N\') AS `Lock_tables_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 262144,\'Y\',\'N\') AS `Execute_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 524288,\'Y\',\'N\') AS `Repl_slave_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 1048576,\'Y\',\'N\') AS `Repl_client_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 2097152,\'Y\',\'N\') AS `Create_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 4194304,\'Y\',\'N\') AS `Show_view_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 8388608,\'Y\',\'N\') AS `Create_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 16777216,\'Y\',\'N\') AS `Alter_routine_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 33554432,\'Y\',\'N\') AS `Create_user_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 67108864,\'Y\',\'N\') AS `Event_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 134217728,\'Y\',\'N\') AS `Trigger_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 268435456,\'Y\',\'N\') AS `Create_tablespace_priv`,if(json_value(`mysql`.`global_priv`.`Priv`,\'$.access\') & 536870912,\'Y\',\'N\') AS `Delete_history_priv`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_type\'),0) + 1,\'\',\'ANY\',\'X509\',\'SPECIFIED\') AS `ssl_type`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.ssl_cipher\'),\'\') AS `ssl_cipher`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_issuer\'),\'\') AS `x509_issuer`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.x509_subject\'),\'\') AS `x509_subject`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_questions\'),0) as unsigned) AS `max_questions`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_updates\'),0) as unsigned) AS `max_updates`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_connections\'),0) as unsigned) AS `max_connections`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_user_connections\'),0) as signed) AS `max_user_connections`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.plugin\'),\'\') AS `plugin`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.authentication_string\'),\'\') AS `authentication_string`,if(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.password_last_changed\'),1) = 0,\'Y\',\'N\') AS `password_expired`,elt(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.is_role\'),0) + 1,\'N\',\'Y\') AS `is_role`,ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.default_role\'),\'\') AS `default_role`,cast(ifnull(json_value(`mysql`.`global_priv`.`Priv`,\'$.max_statement_time\'),0.0) as decimal(12,6)) AS `max_statement_time` from `mysql`.`global_priv` +mariadb-version=100625 diff --git a/mysql-test/suite/encryption/t/innodb-first-page-read.opt b/mysql-test/suite/encryption/t/innodb-first-page-read.opt deleted file mode 100644 index 38d69691ed6..00000000000 --- a/mysql-test/suite/encryption/t/innodb-first-page-read.opt +++ /dev/null @@ -1,5 +0,0 @@ ---innodb-encrypt-tables=ON ---innodb-encrypt-log=ON ---innodb-encryption-rotate-key-age=15 ---innodb-encryption-threads=4 ---innodb-tablespaces-encryption diff --git a/mysql-test/suite/galera/r/MDEV-22232.result b/mysql-test/suite/galera/r/MDEV-22232.result index 6ba9cd7b55b..79db271bc50 100644 --- a/mysql-test/suite/galera/r/MDEV-22232.result +++ b/mysql-test/suite/galera/r/MDEV-22232.result @@ -9,7 +9,7 @@ connection node_1; SET DEBUG_SYNC = 'now WAIT_FOR may_run'; TRUNCATE TABLE t1; connection con1; -Got one of the listed errors +ERROR 70100: Query execution was interrupted SET DEBUG_SYNC = 'RESET'; --- CTAS with non-empty result set --- INSERT INTO t1 VALUES (10), (20), (30); @@ -19,7 +19,7 @@ connection node_1; SET DEBUG_SYNC = 'now WAIT_FOR may_run'; TRUNCATE TABLE t1; connection con1; -Got one of the listed errors +ERROR 70100: Query execution was interrupted SET DEBUG_SYNC = 'RESET'; DROP TABLE t1; disconnect con1; diff --git a/mysql-test/suite/galera/r/MDEV-30418.result b/mysql-test/suite/galera/r/MDEV-30418.result index 67ea6462c41..9f426498360 100644 --- a/mysql-test/suite/galera/r/MDEV-30418.result +++ b/mysql-test/suite/galera/r/MDEV-30418.result @@ -2,7 +2,9 @@ connection node_2; connection node_1; connection node_1; connection node_2; +SET SESSION wsrep_sync_wait=0; connection node_2; +SET SESSION wsrep_sync_wait=0; select @@wsrep_slave_threads; @@wsrep_slave_threads 1 diff --git a/mysql-test/suite/galera/r/MDEV-30612.result b/mysql-test/suite/galera/r/MDEV-30612.result new file mode 100644 index 00000000000..5003d4e68c3 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-30612.result @@ -0,0 +1,11 @@ +connection node_2; +connection node_1; +CREATE TABLE t(a INT) ENGINE=INNODB; +PREPARE s FROM 'CREATE TRIGGER tr AFTER DELETE ON t FOR EACH ROW SET @a=1'; +EXECUTE s; +EXECUTE s; +ERROR HY000: Trigger 'test.tr' already exists +DROP TRIGGER tr; +DROP TABLE t; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/MDEV-39011.result b/mysql-test/suite/galera/r/MDEV-39011.result new file mode 100644 index 00000000000..dc83746435b --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-39011.result @@ -0,0 +1,21 @@ +connection node_2; +connection node_1; +connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connection node_3; +RESET MASTER; +connection node_2; +SET GLOBAL DEBUG_DBUG = "+d,delay_sql_thread_after_release_run_lock"; +START SLAVE; +SET DEBUG_SYNC = "now WAIT_FOR sql_thread_run_lock_released"; +SET GLOBAL DEBUG_DBUG = "+d,wsrep_async_slave_node_dropped_error"; +SET DEBUG_SYNC = "now SIGNAL sql_thread_continue"; +SET DEBUG_SYNC = "now WAIT_FOR sql_thread_run_lock_released"; +SET GLOBAL DEBUG_DBUG = "-d,wsrep_async_slave_node_dropped_error"; +SET DEBUG_SYNC = "now SIGNAL sql_thread_continue"; +SET DEBUG_SYNC = "RESET"; +SET GLOBAL DEBUG_DBUG = ""; +STOP SLAVE; +RESET SLAVE; +connection node_3; +RESET MASTER; +disconnect node_3; diff --git a/mysql-test/suite/galera/r/galera_fk_truncate.result b/mysql-test/suite/galera/r/galera_fk_truncate.result index a90f3e27ab7..cc1c029fada 100644 --- a/mysql-test/suite/galera/r/galera_fk_truncate.result +++ b/mysql-test/suite/galera/r/galera_fk_truncate.result @@ -1,5 +1,12 @@ connection node_2; connection node_1; +connection node_1; +set global auto_increment_offset=1; +set global auto_increment_increment=2; +connection node_2; +set global auto_increment_offset=2; +set global auto_increment_increment=2; +connection node_1; CREATE TABLE author ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL @@ -45,3 +52,6 @@ id name SELECT * FROM book; id title author_id DROP TABLE book, author; +set global auto_increment_increment=2; +connection node_2; +set global auto_increment_offset=2; diff --git a/mysql-test/suite/galera/t/GCF-360.cnf b/mysql-test/suite/galera/t/GCF-360.cnf index 28e51f87e8e..f092f7d358e 100644 --- a/mysql-test/suite/galera/t/GCF-360.cnf +++ b/mysql-test/suite/galera/t/GCF-360.cnf @@ -1,17 +1,4 @@ !include ../galera_4nodes.cnf -[mysqld.1] -wsrep_provider_options='base_port=@mysqld.1.#galera_port' -wsrep_ignore_apply_errors=0 - -[mysqld.2] -wsrep_provider_options='base_port=@mysqld.2.#galera_port' -wsrep_ignore_apply_errors=0 - -[mysqld.3] -wsrep_provider_options='base_port=@mysqld.3.#galera_port' -wsrep_ignore_apply_errors=0 - -[mysqld.4] -wsrep_provider_options='base_port=@mysqld.4.#galera_port' +[mysqld] wsrep_ignore_apply_errors=0 diff --git a/mysql-test/suite/galera/t/MDEV-22232.test b/mysql-test/suite/galera/t/MDEV-22232.test index 473766c6188..087d6417b01 100644 --- a/mysql-test/suite/galera/t/MDEV-22232.test +++ b/mysql-test/suite/galera/t/MDEV-22232.test @@ -31,7 +31,7 @@ TRUNCATE TABLE t1; --connection con1 # CTAS gets BF aborted. ---error ER_QUERY_INTERRUPTED, ER_LOCK_DEADLOCK +--error ER_QUERY_INTERRUPTED --reap # Cleanup @@ -56,7 +56,7 @@ TRUNCATE TABLE t1; --connection con1 # CTAS gets BF aborted. ---error ER_QUERY_INTERRUPTED, ER_LOCK_DEADLOCK +--error ER_QUERY_INTERRUPTED --reap # Cleanup diff --git a/mysql-test/suite/galera/t/MDEV-30418.test b/mysql-test/suite/galera/t/MDEV-30418.test index 740fd8f8b5e..4c5421652f8 100644 --- a/mysql-test/suite/galera/t/MDEV-30418.test +++ b/mysql-test/suite/galera/t/MDEV-30418.test @@ -5,7 +5,9 @@ --let $node_2=node_2 --source ../galera/include/auto_increment_offset_save.inc +SET SESSION wsrep_sync_wait=0; --connection node_2 +SET SESSION wsrep_sync_wait=0; select @@wsrep_slave_threads; SET @cluster_address_orig = @@wsrep_cluster_address; SET GLOBAL wsrep_cluster_address=AUTO; @@ -23,6 +25,13 @@ SHOW WARNINGS; --disable_query_log SET GLOBAL wsrep_cluster_address = @cluster_address_orig; --enable_query_log + +# wait (without using SELECT) for the cluster becoming ready for all SQL statements +let $show_statement= SHOW STATUS LIKE 'wsrep_ready'; +let $field= Value; +let $condition= = 'ON'; +--source include/wait_show_condition.inc + select @@wsrep_slave_threads; show status like 'wsrep_cluster_size'; show status like 'wsrep_cluster_status'; diff --git a/mysql-test/suite/galera/t/MDEV-30612.test b/mysql-test/suite/galera/t/MDEV-30612.test new file mode 100644 index 00000000000..496d8166cd1 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-30612.test @@ -0,0 +1,17 @@ +# +# MDEV-30612: Executing CREATE TRIGGER prepared statement twice led to a crash. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +CREATE TABLE t(a INT) ENGINE=INNODB; +PREPARE s FROM 'CREATE TRIGGER tr AFTER DELETE ON t FOR EACH ROW SET @a=1'; +EXECUTE s; +--error ER_TRG_ALREADY_EXISTS +EXECUTE s; + +DROP TRIGGER tr; +DROP TABLE t; + +--source include/galera_end.inc diff --git a/mysql-test/suite/galera/t/MDEV-39011.cnf b/mysql-test/suite/galera/t/MDEV-39011.cnf new file mode 100644 index 00000000000..37df34b61d8 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-39011.cnf @@ -0,0 +1,7 @@ +!include ../galera_2nodes_as_slave.cnf + +[mysqld.1] +wsrep_restart_slave=1 + +[mysqld.2] +wsrep_restart_slave=1 diff --git a/mysql-test/suite/galera/t/MDEV-39011.test b/mysql-test/suite/galera/t/MDEV-39011.test new file mode 100644 index 00000000000..8214809ae5e --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-39011.test @@ -0,0 +1,48 @@ +# +# MDEV-39011: The node running async slave replication hangs in shutdown. +# The problem was in a leaked THD_count on the error path when +# wsrep_restart_slave is set. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +# node 3 is a native MariaDB server operating as async replication master +--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 +--connection node_3 +RESET MASTER; + +# nodes 1 and 2 form a Galera cluster, node 2 operates as a slave for the +# native MariaDB master in node 3 +--connection node_2 +--disable_query_log +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3; +--enable_query_log + +SET GLOBAL DEBUG_DBUG = "+d,delay_sql_thread_after_release_run_lock"; +START SLAVE; +# Wait for the async slave thread to get started +SET DEBUG_SYNC = "now WAIT_FOR sql_thread_run_lock_released"; +# Simulate a node dropped error for Wsrep to go to the restart point +SET GLOBAL DEBUG_DBUG = "+d,wsrep_async_slave_node_dropped_error"; +SET DEBUG_SYNC = "now SIGNAL sql_thread_continue"; +# Now wait again as the execution should follow the error path and repeat +SET DEBUG_SYNC = "now WAIT_FOR sql_thread_run_lock_released"; +# Don't follow the error path anymore +SET GLOBAL DEBUG_DBUG = "-d,wsrep_async_slave_node_dropped_error"; +SET DEBUG_SYNC = "now SIGNAL sql_thread_continue"; + +# Cleanup before restart +SET DEBUG_SYNC = "RESET"; +SET GLOBAL DEBUG_DBUG = ""; +STOP SLAVE; +RESET SLAVE; + +# Now try to restart the node: it should not hang in a shutdown +--source include/restart_mysqld.inc + +--connection node_3 +RESET MASTER; +--disconnect node_3 diff --git a/mysql-test/suite/galera/t/galera_as_slave_replay.cnf b/mysql-test/suite/galera/t/galera_as_slave_replay.cnf index 80c95e2bfd6..b333eb03247 100644 --- a/mysql-test/suite/galera/t/galera_as_slave_replay.cnf +++ b/mysql-test/suite/galera/t/galera_as_slave_replay.cnf @@ -5,9 +5,7 @@ binlog-format=row loose-galera-slave-replay=1 [mysqld.1] -wsrep_restart_slave=1 wsrep-debug=1 [mysqld.2] -wsrep_restart_slave=1 wsrep-debug=1 diff --git a/mysql-test/suite/galera/t/galera_fk_truncate.cnf b/mysql-test/suite/galera/t/galera_fk_truncate.cnf deleted file mode 100644 index 00e5017455f..00000000000 --- a/mysql-test/suite/galera/t/galera_fk_truncate.cnf +++ /dev/null @@ -1,9 +0,0 @@ -!include ../galera_2nodes.cnf - -[mysqld.1] -auto_increment_offset=1 -auto_increment_increment=2 - -[mysqld.2] -auto_increment_offset=2 -auto_increment_increment=2 diff --git a/mysql-test/suite/galera/t/galera_fk_truncate.test b/mysql-test/suite/galera/t/galera_fk_truncate.test index 61b0f562065..ab2894940f8 100644 --- a/mysql-test/suite/galera/t/galera_fk_truncate.test +++ b/mysql-test/suite/galera/t/galera_fk_truncate.test @@ -1,6 +1,17 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +# +# Make sure earlier test has no effect to this one +# +--connection node_1 +set global auto_increment_offset=1; +set global auto_increment_increment=2; +--connection node_2 +set global auto_increment_offset=2; +set global auto_increment_increment=2; + +--connection node_1 CREATE TABLE author ( id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL @@ -38,3 +49,8 @@ SELECT * FROM author; SELECT * FROM book; DROP TABLE book, author; +set global auto_increment_increment=2; +--connection node_2 +set global auto_increment_offset=2; + + diff --git a/mysql-test/suite/galera_3nodes/r/MDEV-36360.result b/mysql-test/suite/galera_3nodes/r/MDEV-36360.result index 2778c3e7bd8..8d6ee8a9b02 100644 --- a/mysql-test/suite/galera_3nodes/r/MDEV-36360.result +++ b/mysql-test/suite/galera_3nodes/r/MDEV-36360.result @@ -21,7 +21,7 @@ SET SESSION wsrep_on = ON; Restarting server 3 with one applier thread having FK and UK checks disabled SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_after_write_row'; connection node_1; -INSERT INTO child VALUES (1, 1); +INSERT INTO child VALUES (1, 2); connection node_3; SET DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_after_write_row_reached'; SET GLOBAL DEBUG_DBUG = ''; @@ -29,7 +29,6 @@ SET wsrep_sync_wait = 0; SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL signal.wsrep_after_write_row'; INSERT INTO child VALUES (2, 2); SET DEBUG_SYNC = 'RESET'; -include/assert_grep.inc [no FK constraint failure] Server 3 SELECT COUNT(*) AS EXPECT_1 FROM parent; EXPECT_1 diff --git a/mysql-test/suite/galera_3nodes/t/MDEV-36360.test b/mysql-test/suite/galera_3nodes/t/MDEV-36360.test index 31f077fb818..947345ffbdd 100644 --- a/mysql-test/suite/galera_3nodes/t/MDEV-36360.test +++ b/mysql-test/suite/galera_3nodes/t/MDEV-36360.test @@ -61,7 +61,7 @@ SET GLOBAL DEBUG_DBUG = 'd,sync.wsrep_after_write_row'; # Insert a child row that will be applied on node #3, but should not # grab table-level X-lock. --connection node_1 -INSERT INTO child VALUES (1, 1); +INSERT INTO child VALUES (1, 2); --connection node_3 SET DEBUG_SYNC = 'now WAIT_FOR sync.wsrep_after_write_row_reached'; @@ -75,14 +75,6 @@ SET DEBUG_SYNC = 'ib_after_row_insert SIGNAL signal.wsrep_after_write_row'; # grabs table-level X-lock, they'll both deadlock forever. INSERT INTO child VALUES (2, 2); SET DEBUG_SYNC = 'RESET'; - ---let $assert_select = foreign key constraint fails ---let $assert_count = 0 ---let $assert_text = no FK constraint failure ---let $assert_only_after = CURRENT_TEST ---let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.3.err ---source include/assert_grep.inc - # Child row insert is applied even though there's no parent row. --echo Server 3 SELECT COUNT(*) AS EXPECT_1 FROM parent; diff --git a/mysql-test/suite/innodb/r/alter_algorithm.result b/mysql-test/suite/innodb/r/alter_algorithm.result index 055fb3ce688..03e716b79f7 100644 --- a/mysql-test/suite/innodb/r/alter_algorithm.result +++ b/mysql-test/suite/innodb/r/alter_algorithm.result @@ -8,6 +8,12 @@ f4 INT as (f2) STORED, f5 INT as (f3) STORED, PRIMARY KEY(f1))ROW_FORMAT=COMPRESSED, ENGINE=INNODB; INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); +CREATE TABLE t2(f1 INT PRIMARY KEY, f2 INT NOT NULL, +f3 INT AS (f2 * f2) VIRTUAL, +f4 INT NOT NULL UNIQUE, +f5 INT NOT NULL, +INDEX idx(f2))ENGINE=INNODB; +INSERT INTO t2(f1, f2, f4, f5) VALUES(1, 2, 3, 4); # All the following cases needs table rebuild # Add and Drop primary key ALTER TABLE t1 ADD COLUMN col1 INT NOT NULL,DROP PRIMARY KEY,ADD PRIMARY KEY(col1), ALGORITHM=COPY; @@ -44,18 +50,23 @@ info: Records: 1 Duplicates: 0 Warnings: 0 ALTER TABLE t1 FORCE, ALGORITHM=DEFAULT; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t2 page_compressed=1, ALGORITHM=COPY; +affected rows: 1 +info: Records: 1 Duplicates: 0 Warnings: 0 DROP TABLE t1; affected rows: 0 +DROP TABLE t2; +affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, f3 INT AS (f2 * f2) VIRTUAL, f4 INT NOT NULL UNIQUE, f5 INT NOT NULL, -INDEX idx(f2))ENGINE=INNODB; +INDEX idx(f2)) PAGE_COMPRESSED=1, ENGINE=INNODB; CREATE TABLE t2(f1 INT NOT NULL, f2 INT NOT NULL, INDEX(f1), FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); -ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1, ALGORITHM=COPY; +ALTER TABLE t1 ADD INDEX idx1(f4), page_compression_level=7, ALGORITHM=COPY; affected rows: 1 info: Records: 1 Duplicates: 0 Warnings: 0 ALTER TABLE t1 DROP INDEX idx, page_compression_level=5, ALGORITHM=COPY; @@ -132,6 +143,12 @@ f4 INT as (f2) STORED, f5 INT as (f3) STORED, PRIMARY KEY(f1))ROW_FORMAT=COMPRESSED, ENGINE=INNODB; INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); +CREATE TABLE t2(f1 INT PRIMARY KEY, f2 INT NOT NULL, +f3 INT AS (f2 * f2) VIRTUAL, +f4 INT NOT NULL UNIQUE, +f5 INT NOT NULL, +INDEX idx(f2))ENGINE=INNODB; +INSERT INTO t2(f1, f2, f4, f5) VALUES(1, 2, 3, 4); # All the following cases needs table rebuild # Add and Drop primary key ALTER TABLE t1 ADD COLUMN col1 INT NOT NULL,DROP PRIMARY KEY,ADD PRIMARY KEY(col1), ALGORITHM=INPLACE; @@ -168,18 +185,23 @@ info: Records: 0 Duplicates: 0 Warnings: 0 ALTER TABLE t1 FORCE, ALGORITHM=DEFAULT; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t2 page_compressed=1, ALGORITHM=INPLACE; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 DROP TABLE t1; affected rows: 0 +DROP TABLE t2; +affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, f3 INT AS (f2 * f2) VIRTUAL, f4 INT NOT NULL UNIQUE, f5 INT NOT NULL, -INDEX idx(f2))ENGINE=INNODB; +INDEX idx(f2)) PAGE_COMPRESSED=1, ENGINE=INNODB; CREATE TABLE t2(f1 INT NOT NULL, f2 INT NOT NULL, INDEX(f1), FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); -ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1, ALGORITHM=INPLACE; +ALTER TABLE t1 ADD INDEX idx1(f4), page_compression_level=7, ALGORITHM=INPLACE; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 ALTER TABLE t1 DROP INDEX idx, page_compression_level=5, ALGORITHM=INPLACE; @@ -255,6 +277,12 @@ f4 INT as (f2) STORED, f5 INT as (f3) STORED, PRIMARY KEY(f1))ROW_FORMAT=COMPRESSED, ENGINE=INNODB; INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); +CREATE TABLE t2(f1 INT PRIMARY KEY, f2 INT NOT NULL, +f3 INT AS (f2 * f2) VIRTUAL, +f4 INT NOT NULL UNIQUE, +f5 INT NOT NULL, +INDEX idx(f2))ENGINE=INNODB; +INSERT INTO t2(f1, f2, f4, f5) VALUES(1, 2, 3, 4); # All the following cases needs table rebuild # Add and Drop primary key ALTER TABLE t1 ADD COLUMN col1 INT NOT NULL,DROP PRIMARY KEY,ADD PRIMARY KEY(col1), ALGORITHM=NOCOPY; @@ -283,18 +311,22 @@ Got one of the listed errors ALTER TABLE t1 FORCE, ALGORITHM=DEFAULT; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t2 page_compressed=1, ALGORITHM=NOCOPY; +Got one of the listed errors DROP TABLE t1; affected rows: 0 +DROP TABLE t2; +affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, f3 INT AS (f2 * f2) VIRTUAL, f4 INT NOT NULL UNIQUE, f5 INT NOT NULL, -INDEX idx(f2))ENGINE=INNODB; +INDEX idx(f2)) PAGE_COMPRESSED=1, ENGINE=INNODB; CREATE TABLE t2(f1 INT NOT NULL, f2 INT NOT NULL, INDEX(f1), FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); -ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1, ALGORITHM=NOCOPY; +ALTER TABLE t1 ADD INDEX idx1(f4), page_compression_level=7, ALGORITHM=NOCOPY; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 ALTER TABLE t1 DROP INDEX idx, page_compression_level=5, ALGORITHM=NOCOPY; @@ -370,6 +402,12 @@ f4 INT as (f2) STORED, f5 INT as (f3) STORED, PRIMARY KEY(f1))ROW_FORMAT=COMPRESSED, ENGINE=INNODB; INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); +CREATE TABLE t2(f1 INT PRIMARY KEY, f2 INT NOT NULL, +f3 INT AS (f2 * f2) VIRTUAL, +f4 INT NOT NULL UNIQUE, +f5 INT NOT NULL, +INDEX idx(f2))ENGINE=INNODB; +INSERT INTO t2(f1, f2, f4, f5) VALUES(1, 2, 3, 4); # All the following cases needs table rebuild # Add and Drop primary key ALTER TABLE t1 ADD COLUMN col1 INT NOT NULL,DROP PRIMARY KEY,ADD PRIMARY KEY(col1), ALGORITHM=INSTANT; @@ -398,18 +436,22 @@ Got one of the listed errors ALTER TABLE t1 FORCE, ALGORITHM=DEFAULT; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 +ALTER TABLE t2 page_compressed=1, ALGORITHM=INSTANT; +Got one of the listed errors DROP TABLE t1; affected rows: 0 +DROP TABLE t2; +affected rows: 0 CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, f3 INT AS (f2 * f2) VIRTUAL, f4 INT NOT NULL UNIQUE, f5 INT NOT NULL, -INDEX idx(f2))ENGINE=INNODB; +INDEX idx(f2)) PAGE_COMPRESSED=1, ENGINE=INNODB; CREATE TABLE t2(f1 INT NOT NULL, f2 INT NOT NULL, INDEX(f1), FOREIGN KEY fidx(f1) REFERENCES t1(f1))ENGINE=INNODB; INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); -ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1, ALGORITHM=INSTANT; +ALTER TABLE t1 ADD INDEX idx1(f4), page_compression_level=7, ALGORITHM=INSTANT; ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: ADD INDEX. Try ALGORITHM=NOCOPY ALTER TABLE t1 DROP INDEX idx, page_compression_level=5, ALGORITHM=INSTANT; ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: DROP INDEX. Try ALGORITHM=NOCOPY diff --git a/mysql-test/suite/innodb/r/alter_copy_stats.result b/mysql-test/suite/innodb/r/alter_copy_stats.result index b6a04cfa01c..7001c44b63e 100644 --- a/mysql-test/suite/innodb/r/alter_copy_stats.result +++ b/mysql-test/suite/innodb/r/alter_copy_stats.result @@ -113,3 +113,14 @@ Warnings: Warning 1088 Error updating stats for table after table rebuild: Lock wait timeout SET innodb_lock_wait_timeout = @lock_wait_timeout; DROP TABLE t; +# +# MDEV-38882 Assertion in diagnostics area on DDL stats +# +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=InnoDB; +connect con1,localhost,root,,; +ALTER TABLE t1 NOWAIT FORCE, ALGORITHM=COPY;; +connection default; +ALTER TABLE t2 FORCE, ALGORITHM=COPY; +connection con1; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/r/alter_crash.result b/mysql-test/suite/innodb/r/alter_crash.result index 070de6b4063..6c1c20d8524 100644 --- a/mysql-test/suite/innodb/r/alter_crash.result +++ b/mysql-test/suite/innodb/r/alter_crash.result @@ -243,3 +243,35 @@ a b 1 1 2 1 DROP TABLE t1; +# +# MDEV-38079 Crash recovery fails after ALTER TABLE…PAGE_COMPRESSED=1 +# +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INSTANT; +ERROR 0A000: ALGORITHM=INSTANT is not supported. Reason: Changing table options requires the table to be rebuilt. Try ALGORITHM=INPLACE +DROP TABLE t1; +# +# MDEV-38928 Assertion undo_no <= 1 in reset_and_truncate_undo +# during ALTER IGNORE on temporary table +# +CREATE TEMPORARY TABLE t1 (f1 INT) ENGINE=INNODB; +INSERT INTO t1 (f1) VALUES (0),(0); +ALTER IGNORE TABLE t1 FORCE; +DROP TABLE t1; +# +# MDEV-38951 Assertion `0' upon ALTER IGNORE handling duplicate keys +# +CREATE TABLE t1(f1 INT)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1), (1); +ALTER IGNORE TABLE t1 ADD UNIQUE(f1); +CHECK TABLE t1 EXTENDED; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; +# +# MDEV-38993 Assertion `trx->undo_no == 1' fails upon ALTER IGNORE +# +CREATE TABLE t (a INT) ENGINE=InnoDB; +INSERT INTO t VALUES (1),(2),(1),(2); +ALTER IGNORE TABLE t ADD UNIQUE(a); +DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index d98da3242f8..15be7190bfd 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -277,6 +277,7 @@ CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY fk1 (b) REFERENCES t1 (a)) ENGINE=InnoDB; ALTER TABLE t2 DROP FOREIGN KEY fk1, DROP FOREIGN KEY fk1; +ERROR 42000: Can't DROP FOREIGN KEY `fk1`; check that it exists DROP TABLE t2, t1; CREATE TABLE t1 (f VARCHAR(256)) ENGINE=InnoDB; SET SESSION FOREIGN_KEY_CHECKS = OFF; @@ -1223,6 +1224,36 @@ set GLOBAL innodb_fast_shutdown=0; # restart ALTER TABLE t2 FORCE; DROP TABLE t2, t1, t3; +# +# MDEV-19194 ASAN use-after-poison in +# fk_prepare_copy_alter_table upon dropping FK +# +CREATE TABLE t1(f1 INT NOT NULL, KEY(f1))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, +FOREIGN KEY `f1`(f1) REFERENCES t1(f1))ENGINE=InnoDB; +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f0, DROP FOREIGN KEY f0, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f0`; check that it exists +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f0, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f0`; check that it exists +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ERROR 42000: Can't DROP FOREIGN KEY `f1`; check that it exists +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +Warnings: +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +Note 1091 Can't DROP FOREIGN KEY `f1`; check that it exists +DROP TABLE t2, t1; # End of 10.6 tests CREATE TABLE t1 ( diff --git a/mysql-test/suite/innodb/r/innodb_ctype_ldml.result b/mysql-test/suite/innodb/r/innodb_ctype_ldml.result index 50294958549..609c98f52d6 100644 --- a/mysql-test/suite/innodb/r/innodb_ctype_ldml.result +++ b/mysql-test/suite/innodb/r/innodb_ctype_ldml.result @@ -474,8 +474,8 @@ SET NAMES utf8; SELECT hex(weight_string(_utf8mb4'a' collate utf8mb4_test_400_ci)); hex(weight_string(_utf8mb4'a' collate utf8mb4_test_400_ci)) 0E33 -SELECT hex(weight_string(convert(_utf32 0x10002 using utf8mb4) collate utf8mb4_test_400_ci)) AS 'Must be FFFD'; -Must be FFFD +SELECT hex(weight_string(convert(_utf32 0x10002 using utf8mb4) collate utf8mb4_test_400_ci)) AS hex_ws; +hex_ws FFFD SELECT hex(@a:=convert(_utf32 0x10400 using utf8mb4) collate utf8mb4_test_400_ci), hex(lower(@a)); hex(@a:=convert(_utf32 0x10400 using utf8mb4) collate utf8mb4_test_400_ci) hex(lower(@a)) @@ -951,7 +951,7 @@ HEX(WEIGHT_STRING(a)) HEX(CONVERT(a USING ucs2)) HEX(a) 15D3 09B809CD E0A6B8E0A78D 15D4 09B909CD E0A6B9E0A78D SELECT HEX(WEIGHT_STRING(a)) as wa, -GROUP_CONCAT(HEX(CONVERT(a USING ucs2)) ORDER BY LENGTH(a), BINARY a) gc +GROUP_CONCAT(HEX(CONVERT(a USING ucs2)) ORDER BY LENGTH(a), BINARY a) AS gc FROM t1 GROUP BY a ORDER BY a; wa gc 15A2 0985 diff --git a/mysql-test/suite/innodb/r/log_corruption_recovery.result b/mysql-test/suite/innodb/r/log_corruption_recovery.result index 54bbe092f90..986e396d965 100644 --- a/mysql-test/suite/innodb/r/log_corruption_recovery.result +++ b/mysql-test/suite/innodb/r/log_corruption_recovery.result @@ -5,7 +5,7 @@ call mtr.add_suppression("InnoDB: OPT_PAGE_CHECKSUM mismatch on \\[page id: spac call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1"); call mtr.add_suppression("InnoDB: Cannot apply log to \\[page id: space=127, page number=0\\] of corrupted file '.*test/t\\.ibd"); call mtr.add_suppression("(InnoDB: Plugin|Plugin 'InnoDB')"); -call mtr.add_suppression("InnoDB: Page .* Current system log sequence number 12(3(38|54|70|86)|4(02|18|34|50|66|82|98))"); +call mtr.add_suppression("InnoDB: Page .* Current system log sequence number 123(38|54)"); SET GLOBAL innodb_fast_shutdown=0; # restart SELECT * FROM INFORMATION_SCHEMA.ENGINES diff --git a/mysql-test/suite/innodb/r/log_file_size,release.rdiff b/mysql-test/suite/innodb/r/log_file_size,release.rdiff new file mode 100644 index 00000000000..c1ca61dbabc --- /dev/null +++ b/mysql-test/suite/innodb/r/log_file_size,release.rdiff @@ -0,0 +1,37 @@ +--- log_file_size.result ++++ log_file_size,release.result +@@ -21,8 +21,6 @@ + 42 + INSERT INTO t1 VALUES (0),(123); + BEGIN; +-SET GLOBAL innodb_limit_optimistic_insert_debug=2; +-INSERT INTO t1 VALUES (124),(125),(126),(127),(128),(129); + DELETE FROM t1 WHERE a>0; + # Persist the state of the above incomplete transaction by + # causing a redo log write for another transaction. +@@ -36,19 +34,6 @@ + SELECT * FROM t1; + ERROR 42000: Unknown storage engine 'InnoDB' + FOUND 1 /syntax error in innodb_log_group_home_dir/ in mysqld.1.err +-# restart: --debug-dbug=d,innodb_log_abort_1 +-SELECT * FROM t1; +-ERROR 42000: Unknown storage engine 'InnoDB' +-FOUND 1 /InnoDB: Starting crash recovery from checkpoint LSN=.*/ in mysqld.1.err +-# restart: --innodb-log-file-size=5M +-SELECT * FROM t1; +-a +-42 +-123 +-# restart: --debug-dbug=d,innodb_log_abort_5 +-SELECT * FROM t1; +-ERROR 42000: Unknown storage engine 'InnoDB' +-FOUND 1 /redo log from 5\.000MiB to [0-9.]*[KMGT]iB/ in mysqld.1.err + # restart + SELECT * FROM t1; + a +@@ -70,4 +55,4 @@ + 42 + 123 + DROP TABLE t1; +-FOUND 2 /InnoDB: Resizing redo log from 5\.000MiB to [0-9.]*[KMGT]iB; LSN=\d+\b/ in mysqld.1.err ++FOUND 1 /InnoDB: Resizing redo log from 5\.000MiB to [0-9.]*[KMGT]iB; LSN=\d+\b/ in mysqld.1.err diff --git a/mysql-test/suite/innodb/r/log_file_size.result b/mysql-test/suite/innodb/r/log_file_size.result index 71fe06cf23b..827c962ac36 100644 --- a/mysql-test/suite/innodb/r/log_file_size.result +++ b/mysql-test/suite/innodb/r/log_file_size.result @@ -1,3 +1,6 @@ +SET GLOBAL innodb_file_per_table=0; +Warnings: +Warning 1287 '@@innodb_file_per_table' is deprecated and will be removed in a future release CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; # restart: --innodb-log-file-size=4m CHECK TABLE t1; @@ -18,6 +21,8 @@ a 42 INSERT INTO t1 VALUES (0),(123); BEGIN; +SET GLOBAL innodb_limit_optimistic_insert_debug=2; +INSERT INTO t1 VALUES (124),(125),(126),(127),(128),(129); DELETE FROM t1 WHERE a>0; # Persist the state of the above incomplete transaction by # causing a redo log write for another transaction. @@ -35,18 +40,20 @@ FOUND 1 /syntax error in innodb_log_group_home_dir/ in mysqld.1.err SELECT * FROM t1; ERROR 42000: Unknown storage engine 'InnoDB' FOUND 1 /InnoDB: Starting crash recovery from checkpoint LSN=.*/ in mysqld.1.err -# restart: --innodb-read-only +# restart: --innodb-log-file-size=5M SELECT * FROM t1; -ERROR 42000: Unknown storage engine 'InnoDB' -FOUND 1 /InnoDB: innodb_read_only prevents crash recovery/ in mysqld.1.err +a +42 +123 # restart: --debug-dbug=d,innodb_log_abort_5 SELECT * FROM t1; ERROR 42000: Unknown storage engine 'InnoDB' FOUND 1 /redo log from 5\.000MiB to [0-9.]*[KMGT]iB/ in mysqld.1.err -# restart: --innodb-read-only +# restart SELECT * FROM t1; -ERROR 42000: Unknown storage engine 'InnoDB' -FOUND 2 /InnoDB: innodb_read_only prevents crash recovery/ in mysqld.1.err +a +42 +123 # restart SELECT * FROM t1; ERROR 42000: Unknown storage engine 'InnoDB' diff --git a/mysql-test/suite/innodb/r/stat_tables.result b/mysql-test/suite/innodb/r/stat_tables.result index 55dfcc3dabc..a9dd4cd5c2f 100644 --- a/mysql-test/suite/innodb/r/stat_tables.result +++ b/mysql-test/suite/innodb/r/stat_tables.result @@ -111,3 +111,16 @@ test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK DROP TABLE t1; # End of 10.11 tests +# +# MDEV-38832 Assertion `!commit_lsn' failed in void trx_t::free() +# +CREATE DATABASE test_1; +CREATE TABLE test_1.t1(f1 INT NOT NULL)Engine=InnoDB; +SET @old_stats=@@global.innodb_stats_persistent; +SET @flush_log_at_commit=@@global.innodb_flush_log_at_trx_commit; +SET GLOBAL innodb_stats_persistent=OFF; +SET GLOBAL innodb_flush_log_at_trx_commit=0; +DROP TABLE test_1.t1; +DROP DATABASE test_1; +SET GLOBAL innodb_stats_persistent=@old_stats; +SET GLOBAL innodb_flush_log_at_trx_commit=@flush_log_at_commit; diff --git a/mysql-test/suite/innodb/r/table_flags.result b/mysql-test/suite/innodb/r/table_flags.result index 24a3ec9b0d8..40d76cf1758 100644 --- a/mysql-test/suite/innodb/r/table_flags.result +++ b/mysql-test/suite/innodb/r/table_flags.result @@ -187,13 +187,16 @@ INSERT INTO t1 VALUES(2); # restart DROP TABLE t1; # -# MDEV-34222 Alter operation on redundant table aborts the server +# MDEV-38079 Crash recovery fails after ALTER TABLE…PAGE_COMPRESSED=1 # SET @df_row = @@global.INNODB_DEFAULT_ROW_FORMAT; SET GLOBAL INNODB_DEFAULT_ROW_FORMAT=REDUNDANT; CREATE TABLE t1 (c CHAR(1)) ENGINE=InnoDB; +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INPLACE; +ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'PAGE_COMPRESSED' +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=COPY; +ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options") SET GLOBAL INNODB_DEFAULT_ROW_FORMAT=compact; -ALTER TABLE t1 PAGE_COMPRESSED=1; -ERROR HY000: Table storage engine 'InnoDB' does not support the create option 'PAGE_COMPRESSED=1 ROW_FORMAT=REDUNDANT' +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=COPY; DROP TABLE t1; SET @@global.INNODB_DEFAULT_ROW_FORMAT = @df_row; diff --git a/mysql-test/suite/innodb/r/undo_upgrade_debug.result b/mysql-test/suite/innodb/r/undo_upgrade_debug.result index 9c464459b98..eb606b54a02 100644 --- a/mysql-test/suite/innodb/r/undo_upgrade_debug.result +++ b/mysql-test/suite/innodb/r/undo_upgrade_debug.result @@ -27,16 +27,12 @@ undo002 undo001 undo002 undo003 -# case 4: Abort after re-creating new undo tablespaces -# restart: --innodb_undo_tablespaces=4 --debug_dbug=+d,after_reinit_undo_abort # restart: --innodb_undo_tablespaces=4 # Should list 4 undo log tablespaces undo001 undo002 undo003 undo004 -# case 5: Abort after re-creating new undo tablespaces successfully -# restart: --innodb_undo_tablespaces=2 --debug_dbug=+d,after_reinit_undo_success # restart: --innodb_undo_tablespaces=2 # Should list 2 undo log tablespaces undo001 diff --git a/mysql-test/suite/innodb/r/xa_recovery.result b/mysql-test/suite/innodb/r/xa_recovery.result index a77b42e3256..23af0484ae6 100644 --- a/mysql-test/suite/innodb/r/xa_recovery.result +++ b/mysql-test/suite/innodb/r/xa_recovery.result @@ -16,6 +16,7 @@ connection default; disconnect con1; disconnect con2; connect con1,localhost,root; +SET STATEMENT innodb_lock_wait_timeout=1 FOR # work around MDEV-38741 SELECT * FROM t1 LOCK IN SHARE MODE; connection default; SET innodb_lock_wait_timeout=1; diff --git a/mysql-test/suite/innodb/t/alter_algorithm.inc b/mysql-test/suite/innodb/t/alter_algorithm.inc index ba1d449a182..eff42fa2769 100644 --- a/mysql-test/suite/innodb/t/alter_algorithm.inc +++ b/mysql-test/suite/innodb/t/alter_algorithm.inc @@ -21,6 +21,13 @@ CREATE TABLE t1(f1 INT NOT NULL, PRIMARY KEY(f1))ROW_FORMAT=COMPRESSED, ENGINE=INNODB; INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); +CREATE TABLE t2(f1 INT PRIMARY KEY, f2 INT NOT NULL, + f3 INT AS (f2 * f2) VIRTUAL, + f4 INT NOT NULL UNIQUE, + f5 INT NOT NULL, + INDEX idx(f2))ENGINE=INNODB; +INSERT INTO t2(f1, f2, f4, f5) VALUES(1, 2, 3, 4); + --enable_info --echo # All the following cases needs table rebuild @@ -58,7 +65,11 @@ INSERT INTO t1(f1, f2, f3) VALUES(1, 1, 1); ALTER TABLE t1 FORCE, ALGORITHM=DEFAULT; +--error $error_code +eval ALTER TABLE t2 page_compressed=1, ALGORITHM=$alter_algorithm; + DROP TABLE t1; +DROP TABLE t2; --disable_info if ($algorithm == "NOCOPY") { @@ -73,7 +84,7 @@ CREATE TABLE t1(f1 INT PRIMARY KEY, f2 INT NOT NULL, f3 INT AS (f2 * f2) VIRTUAL, f4 INT NOT NULL UNIQUE, f5 INT NOT NULL, - INDEX idx(f2))ENGINE=INNODB; + INDEX idx(f2)) PAGE_COMPRESSED=1, ENGINE=INNODB; CREATE TABLE t2(f1 INT NOT NULL, f2 INT NOT NULL, INDEX(f1), @@ -83,7 +94,7 @@ INSERT INTO t1(f1, f2, f4, f5) VALUES(1, 2, 3, 4); --enable_info --error $error_code ---eval ALTER TABLE t1 ADD INDEX idx1(f4), page_compressed=1, ALGORITHM=$alter_algorithm +--eval ALTER TABLE t1 ADD INDEX idx1(f4), page_compression_level=7, ALGORITHM=$alter_algorithm --error $error_code --eval ALTER TABLE t1 DROP INDEX idx, page_compression_level=5, ALGORITHM=$alter_algorithm diff --git a/mysql-test/suite/innodb/t/alter_copy_stats.test b/mysql-test/suite/innodb/t/alter_copy_stats.test index 4a0b905e8e4..c065f825af1 100644 --- a/mysql-test/suite/innodb/t/alter_copy_stats.test +++ b/mysql-test/suite/innodb/t/alter_copy_stats.test @@ -97,3 +97,19 @@ SET innodb_lock_wait_timeout = 1; CREATE TABLE t ENGINE=InnoDB AS SELECT * FROM mysql.innodb_table_stats; SET innodb_lock_wait_timeout = @lock_wait_timeout; DROP TABLE t; + +--echo # +--echo # MDEV-38882 Assertion in diagnostics area on DDL stats +--echo # +CREATE TABLE t1 (a INT) ENGINE=InnoDB; +CREATE TABLE t2 (pk INT PRIMARY KEY) ENGINE=InnoDB; +--connect (con1,localhost,root,,) +--send ALTER TABLE t1 NOWAIT FORCE, ALGORITHM=COPY; +--connection default +ALTER TABLE t2 FORCE, ALGORITHM=COPY; +--disable_warnings +--connection con1 +--error 0,ER_LOCK_WAIT_TIMEOUT +--reap +--enable_warnings +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/t/alter_crash.test b/mysql-test/suite/innodb/t/alter_crash.test index 1829529450d..6f2debb11ed 100644 --- a/mysql-test/suite/innodb/t/alter_crash.test +++ b/mysql-test/suite/innodb/t/alter_crash.test @@ -241,3 +241,37 @@ CHECK TABLE t1; SHOW CREATE TABLE t1; SELECT * FROM t1; DROP TABLE t1; + +--echo # +--echo # MDEV-38079 Crash recovery fails after ALTER TABLE…PAGE_COMPRESSED=1 +--echo # +CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; +--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INSTANT; +DROP TABLE t1; + +--echo # +--echo # MDEV-38928 Assertion undo_no <= 1 in reset_and_truncate_undo +--echo # during ALTER IGNORE on temporary table +--echo # +CREATE TEMPORARY TABLE t1 (f1 INT) ENGINE=INNODB; +INSERT INTO t1 (f1) VALUES (0),(0); +ALTER IGNORE TABLE t1 FORCE; +DROP TABLE t1; + +--echo # +--echo # MDEV-38951 Assertion `0' upon ALTER IGNORE handling duplicate keys +--echo # +CREATE TABLE t1(f1 INT)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1), (1); +ALTER IGNORE TABLE t1 ADD UNIQUE(f1); +CHECK TABLE t1 EXTENDED; +DROP TABLE t1; + +--echo # +--echo # MDEV-38993 Assertion `trx->undo_no == 1' fails upon ALTER IGNORE +--echo # +CREATE TABLE t (a INT) ENGINE=InnoDB; +INSERT INTO t VALUES (1),(2),(1),(2); +ALTER IGNORE TABLE t ADD UNIQUE(a); +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 6ce39363690..88033e89130 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -256,6 +256,7 @@ DROP TABLE t1; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t2 (b INT PRIMARY KEY, FOREIGN KEY fk1 (b) REFERENCES t1 (a)) ENGINE=InnoDB; +--error ER_CANT_DROP_FIELD_OR_KEY ALTER TABLE t2 DROP FOREIGN KEY fk1, DROP FOREIGN KEY fk1; DROP TABLE t2, t1; @@ -1271,6 +1272,30 @@ set GLOBAL innodb_fast_shutdown=0; ALTER TABLE t2 FORCE; DROP TABLE t2, t1, t3; +--echo # +--echo # MDEV-19194 ASAN use-after-poison in +--echo # fk_prepare_copy_alter_table upon dropping FK +--echo # +CREATE TABLE t1(f1 INT NOT NULL, KEY(f1))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, + FOREIGN KEY `f1`(f1) REFERENCES t1(f1))ENGINE=InnoDB; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f0, DROP FOREIGN KEY f0, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f0, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER IGNORE TABLE t2 DROP FOREIGN KEY f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +--error ER_CANT_DROP_FIELD_OR_KEY +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY f1, ALGORITHM=COPY; +ALTER TABLE t2 DROP FOREIGN KEY IF EXISTS f1, DROP FOREIGN KEY IF EXISTS f1, ALGORITHM=COPY; +DROP TABLE t2, t1; + --echo # End of 10.6 tests CREATE TABLE t1 diff --git a/mysql-test/suite/innodb/t/innodb_ctype_ldml.test b/mysql-test/suite/innodb/t/innodb_ctype_ldml.test index fc717eb7d47..3f8980309ea 100644 --- a/mysql-test/suite/innodb/t/innodb_ctype_ldml.test +++ b/mysql-test/suite/innodb/t/innodb_ctype_ldml.test @@ -207,7 +207,7 @@ SET NAMES utf8; # make sure utf8mb4_test_400_ci is Unicode-4.0.0 based SELECT hex(weight_string(_utf8mb4'a' collate utf8mb4_test_400_ci)); -SELECT hex(weight_string(convert(_utf32 0x10002 using utf8mb4) collate utf8mb4_test_400_ci)) AS 'Must be FFFD'; +SELECT hex(weight_string(convert(_utf32 0x10002 using utf8mb4) collate utf8mb4_test_400_ci)) AS hex_ws; SELECT hex(@a:=convert(_utf32 0x10400 using utf8mb4) collate utf8mb4_test_400_ci), hex(lower(@a)); SELECT hex(@a:=convert(_utf32 0x10428 using utf8mb4) collate utf8mb4_test_400_ci), hex(upper(@a)); SELECT hex(@a:=convert(_utf32 0x2C00 using utf8mb4) collate utf8mb4_test_400_ci), hex(lower(@a)); @@ -344,7 +344,7 @@ INSERT INTO t1 VALUES SELECT HEX(WEIGHT_STRING(a)), HEX(CONVERT(a USING ucs2)), HEX(a) FROM t1 ORDER BY a, BINARY(a); SELECT HEX(WEIGHT_STRING(a)) as wa, -GROUP_CONCAT(HEX(CONVERT(a USING ucs2)) ORDER BY LENGTH(a), BINARY a) gc +GROUP_CONCAT(HEX(CONVERT(a USING ucs2)) ORDER BY LENGTH(a), BINARY a) AS gc FROM t1 GROUP BY a ORDER BY a; DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/log_corruption_recovery.test b/mysql-test/suite/innodb/t/log_corruption_recovery.test index 489010f9b77..0a7603a5ee0 100644 --- a/mysql-test/suite/innodb/t/log_corruption_recovery.test +++ b/mysql-test/suite/innodb/t/log_corruption_recovery.test @@ -15,7 +15,7 @@ call mtr.add_suppression("InnoDB: Set innodb_force_recovery=1"); call mtr.add_suppression("InnoDB: Cannot apply log to \\[page id: space=127, page number=0\\] of corrupted file '.*test/t\\.ibd"); call mtr.add_suppression("(InnoDB: Plugin|Plugin 'InnoDB')"); # Allow innodb_force_recovery=1 to write up to 10 FILE_CHECKPOINT records -call mtr.add_suppression("InnoDB: Page .* Current system log sequence number 12(3(38|54|70|86)|4(02|18|34|50|66|82|98))"); +call mtr.add_suppression("InnoDB: Page .* Current system log sequence number 123(38|54)"); SET GLOBAL innodb_fast_shutdown=0; --source include/shutdown_mysqld.inc --move_file $DATADIR/ib_logfile0 $DATADIR/ib_logfile0.old diff --git a/mysql-test/suite/innodb/t/log_file_size.test b/mysql-test/suite/innodb/t/log_file_size.test index 01fcb84860a..a4f85c2b938 100644 --- a/mysql-test/suite/innodb/t/log_file_size.test +++ b/mysql-test/suite/innodb/t/log_file_size.test @@ -2,8 +2,7 @@ --source include/innodb_page_size_small.inc # Embedded server tests do not support restarting --source include/not_embedded.inc -# DBUG_EXECUTE_IF is needed ---source include/have_debug.inc +--source include/maybe_debug.inc # This test is slow on buildbot. --source include/big_test.inc @@ -20,6 +19,7 @@ call mtr.add_suppression("InnoDB: Expecting only ib_logfile0"); FLUSH TABLES; --enable_query_log let MYSQLD_DATADIR= `select @@datadir`; +SET GLOBAL innodb_file_per_table=0; CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=InnoDB; --source include/shutdown_mysqld.inc @@ -89,6 +89,10 @@ INSERT INTO t1 VALUES (0),(123); let SEARCH_ABORT = NOT FOUND; BEGIN; +if ($have_debug) { +SET GLOBAL innodb_limit_optimistic_insert_debug=2; +INSERT INTO t1 VALUES (124),(125),(126),(127),(128),(129); +} DELETE FROM t1 WHERE a>0; --echo # Persist the state of the above incomplete transaction by @@ -107,22 +111,23 @@ DELETE FROM t1 WHERE a=0; SELECT * FROM t1; let SEARCH_PATTERN= syntax error in innodb_log_group_home_dir; --source include/search_pattern_in_file.inc +--let $restart_parameters= +if ($have_debug) { --let $restart_parameters= --debug-dbug=d,innodb_log_abort_1 --source include/restart_mysqld.inc --error ER_UNKNOWN_STORAGE_ENGINE SELECT * FROM t1; let SEARCH_PATTERN= InnoDB: Starting crash recovery from checkpoint LSN=.*; --source include/search_pattern_in_file.inc +let $restart_parameters = --innodb-log-file-size=5M; +} ---let $restart_parameters= --innodb-read-only --source include/restart_mysqld.inc ---error ER_UNKNOWN_STORAGE_ENGINE SELECT * FROM t1; -let SEARCH_PATTERN= InnoDB: innodb_read_only prevents crash recovery; ---source include/search_pattern_in_file.inc +if ($have_debug) { --let $restart_parameters= --debug-dbug=d,innodb_log_abort_5 --source include/restart_mysqld.inc --error ER_UNKNOWN_STORAGE_ENGINE @@ -130,12 +135,10 @@ SELECT * FROM t1; let SEARCH_PATTERN= redo log from 5\\.000MiB to [0-9.]*[KMGT]iB; --source include/search_pattern_in_file.inc ---let $restart_parameters= --innodb-read-only +--let $restart_parameters= --source include/restart_mysqld.inc ---error ER_UNKNOWN_STORAGE_ENGINE SELECT * FROM t1; -let SEARCH_PATTERN= InnoDB: innodb_read_only prevents crash recovery; ---source include/search_pattern_in_file.inc +} # Trigger an error in recovery. diff --git a/mysql-test/suite/innodb/t/stat_tables.test b/mysql-test/suite/innodb/t/stat_tables.test index f5eef1e9056..f41e7cd7450 100644 --- a/mysql-test/suite/innodb/t/stat_tables.test +++ b/mysql-test/suite/innodb/t/stat_tables.test @@ -119,3 +119,17 @@ SET STATEMENT transaction_read_only=1 FOR ANALYZE TABLE t1; DROP TABLE t1; --echo # End of 10.11 tests + +--echo # +--echo # MDEV-38832 Assertion `!commit_lsn' failed in void trx_t::free() +--echo # +CREATE DATABASE test_1; +CREATE TABLE test_1.t1(f1 INT NOT NULL)Engine=InnoDB; +SET @old_stats=@@global.innodb_stats_persistent; +SET @flush_log_at_commit=@@global.innodb_flush_log_at_trx_commit; +SET GLOBAL innodb_stats_persistent=OFF; +SET GLOBAL innodb_flush_log_at_trx_commit=0; +DROP TABLE test_1.t1; +DROP DATABASE test_1; +SET GLOBAL innodb_stats_persistent=@old_stats; +SET GLOBAL innodb_flush_log_at_trx_commit=@flush_log_at_commit; diff --git a/mysql-test/suite/innodb/t/table_flags.test b/mysql-test/suite/innodb/t/table_flags.test index 74a7782a90f..40193b99c86 100644 --- a/mysql-test/suite/innodb/t/table_flags.test +++ b/mysql-test/suite/innodb/t/table_flags.test @@ -257,13 +257,16 @@ let $shutdown_timeout = 0; DROP TABLE t1; --echo # ---echo # MDEV-34222 Alter operation on redundant table aborts the server +--echo # MDEV-38079 Crash recovery fails after ALTER TABLE…PAGE_COMPRESSED=1 --echo # SET @df_row = @@global.INNODB_DEFAULT_ROW_FORMAT; SET GLOBAL INNODB_DEFAULT_ROW_FORMAT=REDUNDANT; CREATE TABLE t1 (c CHAR(1)) ENGINE=InnoDB; -SET GLOBAL INNODB_DEFAULT_ROW_FORMAT=compact; --error ER_ILLEGAL_HA_CREATE_OPTION -ALTER TABLE t1 PAGE_COMPRESSED=1; +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=INPLACE; +--error ER_CANT_CREATE_TABLE +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=COPY; +SET GLOBAL INNODB_DEFAULT_ROW_FORMAT=compact; +ALTER TABLE t1 PAGE_COMPRESSED=1, ALGORITHM=COPY; DROP TABLE t1; SET @@global.INNODB_DEFAULT_ROW_FORMAT = @df_row; diff --git a/mysql-test/suite/innodb/t/undo_upgrade_debug.test b/mysql-test/suite/innodb/t/undo_upgrade_debug.test index e274d6c020d..f8a40b22d97 100644 --- a/mysql-test/suite/innodb/t/undo_upgrade_debug.test +++ b/mysql-test/suite/innodb/t/undo_upgrade_debug.test @@ -47,22 +47,12 @@ let $restart_parameters=--innodb_undo_tablespaces=3; --echo # Should list 3 undo log tablespaces list_files $MYSQLD_DATADIR undo*; ---echo # case 4: Abort after re-creating new undo tablespaces -let $restart_parameters=--innodb_undo_tablespaces=4 --debug_dbug="+d,after_reinit_undo_abort"; - ---source include/restart_mysqld.inc - let $restart_parameters=--innodb_undo_tablespaces=4; --source include/restart_mysqld.inc --echo # Should list 4 undo log tablespaces list_files $MYSQLD_DATADIR undo*; ---echo # case 5: Abort after re-creating new undo tablespaces successfully -let $restart_parameters=--innodb_undo_tablespaces=2 --debug_dbug="+d,after_reinit_undo_success"; - ---source include/restart_mysqld.inc - let $restart_parameters=--innodb_undo_tablespaces=2; --source include/restart_mysqld.inc diff --git a/mysql-test/suite/innodb/t/xa_recovery.test b/mysql-test/suite/innodb/t/xa_recovery.test index e3479f6fe78..d6498120719 100644 --- a/mysql-test/suite/innodb/t/xa_recovery.test +++ b/mysql-test/suite/innodb/t/xa_recovery.test @@ -31,13 +31,15 @@ connection default; disconnect con1; disconnect con2; connect (con1,localhost,root); ---send SELECT * FROM t1 LOCK IN SHARE MODE +send +SET STATEMENT innodb_lock_wait_timeout=1 FOR # work around MDEV-38741 +SELECT * FROM t1 LOCK IN SHARE MODE; connection default; let $wait_condition= select count(*) = 1 from information_schema.processlist where state = 'Sending data' and - info = 'SELECT * FROM t1 LOCK IN SHARE MODE'; + info LIKE 'SET STATEMENT innodb_lock_wait_timeout%'; --source include/wait_condition.inc SET innodb_lock_wait_timeout=1; diff --git a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result index aa1aae1ee0f..1f680950c7d 100644 --- a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result @@ -140,14 +140,10 @@ tab 1 idx6 1 c4 A # 10 NULL BTREE NO SET @g1 = ST_GeomFromText('POLYGON((20 20,30 30,40 40,50 50,40 50,30 40,30 30,20 20))'); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) -2 POINT(20 20) POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50)) -1 POINT(10 10) POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) UPDATE tab SET C2 = ST_GeomFromText('POINT(1000 1000)') WHERE ST_Crosses(tab.c4, @g1); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) -2 POINT(1000 1000) POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50)) -1 POINT(1000 1000) POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) DELETE FROM tab WHERE ST_Crosses(tab.c4, @g1); ALTER TABLE tab CHANGE COLUMN c2 c22 POINT NOT NULL; affected rows: 0 @@ -232,18 +228,20 @@ DELETE FROM tab WHERE MBREquals(tab.c4, @g1); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE MBREquals(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) ALTER TABLE tab DROP PRIMARY KEY; -affected rows: 4 -info: Records: 4 Duplicates: 0 Warnings: 0 +affected rows: 6 +info: Records: 6 Duplicates: 0 Warnings: 0 ALTER TABLE tab ADD PRIMARY KEY(c2) ; affected rows: 0 info: Records: 0 Duplicates: 0 Warnings: 0 SET @g1 = ST_GeomFromText( 'POLYGON((0 0,0 30,30 40,40 50,50 30,0 0))'); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE ST_Touches(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) +2 POINT(20 20) POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50)) UPDATE tab SET C2 = ST_GeomFromText('POINT(3000 3000)') WHERE ST_Touches(tab.c4, @g1); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE ST_Touches(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) +2 POINT(3000 3000) POLYGON((40 50,40 70,50 100,70 100,80 80,70 50,40 50)) DELETE FROM tab WHERE ST_Touches(tab.c4, @g1); SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE ST_Touches(tab.c4, @g1); c1 ST_Astext(c2) ST_Astext(c4) @@ -267,6 +265,7 @@ Table Op Msg_type Msg_text test.tab check status OK SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab ORDER BY c1; c1 ST_Astext(c2) ST_Astext(c4) +1 POINT(10 10) POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) 6 POINT(3 3) POLYGON((2010 2010,2020 2020,2030 2030,2040 2030,2020 2010,2010 2010)) 7 POINT(60 70) POLYGON((3010 3010,3020 3020,3030 3030,3040 3030,3020 3010,3010 3010)) 8 POINT(0 0) POLYGON((3010 3010,3020 3020,3030 3030,3040 3030,3020 3010,3010 3010)) @@ -290,8 +289,8 @@ SELECT c1,ST_Astext(c2),ST_Astext(c4) FROM tab WHERE MBROverlaps(tab.c4, @g1) OR c1 ST_Astext(c2) ST_Astext(c4) INSERT INTO tab SELECT * FROM tab1; ALTER TABLE tab DROP PRIMARY KEY; -affected rows: 1 -info: Records: 1 Duplicates: 0 Warnings: 0 +affected rows: 2 +info: Records: 2 Duplicates: 0 Warnings: 0 SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TEMPORARY TABLE temp_tab AS SELECT * FROM tab where c1 = c2; ERROR HY000: Illegal parameter data types int and point for operation '=' diff --git a/mysql-test/suite/innodb_gis/r/create_spatial_index.result b/mysql-test/suite/innodb_gis/r/create_spatial_index.result index 7948446ac7b..f8d4df523ad 100644 --- a/mysql-test/suite/innodb_gis/r/create_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/create_spatial_index.result @@ -111,7 +111,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab index idx3 PRIMARY 4 NULL 10 Using where SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -4 POLYGON((300 300,400 400,500 500,300 500,300 400,300 300)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra @@ -125,7 +124,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab index idx3 PRIMARY 4 NULL 10 Using where SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -1 POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra @@ -429,7 +427,6 @@ test.tab check status OK SET @g1 = ST_GeomFromText('POLYGON((100 200,1010 1010,1020 1020,500 300,300 200,100 300,100 200))'); SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -5 POLYGON((1010 1010,1020 1020,1030 1030,1040 1030,1020 1010,1010 1010)) DELETE FROM tab WHERE ST_Crosses(tab.c4, @g1); SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) @@ -555,7 +552,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab range idx3 idx3 34 NULL 1 Using where; Using filesort SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -4 POLYGON((300 300,400 400,500 500,300 500,300 400,300 300)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra @@ -569,7 +565,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab range idx3 idx3 34 NULL 1 Using where; Using filesort SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -1 POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra @@ -864,7 +859,6 @@ test.tab check status OK SET @g1 = ST_GeomFromText('POLYGON((100 200,200 300,400 500,500 300,300 200,100 300,100 200))'); SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -4 POLYGON((300 300,400 400,500 500,300 500,300 400,300 300)) DELETE FROM tab WHERE ST_Crosses(tab.c4, @g1); SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) @@ -989,7 +983,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab index idx3 PRIMARY 4 NULL 10 Using where SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -4 POLYGON((300 300,400 400,500 500,300 500,300 400,300 300)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra @@ -1003,7 +996,6 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE tab index idx3 PRIMARY 4 NULL 10 Using where SELECT c1,ST_Astext(c4) FROM tab WHERE ST_Crosses(tab.c4, @g1) ORDER BY c1; c1 ST_Astext(c4) -1 POLYGON((30 30,40 40,50 50,30 50,30 40,30 30)) EXPLAIN UPDATE tab SET C2 = ST_GeomFromText('POINT(0 0)') WHERE ST_Crosses(tab.c4, @g1); id select_type table type possible_keys key key_len ref rows Extra diff --git a/mysql-test/suite/merge/merge.result b/mysql-test/suite/merge/merge.result index 679f3fbd312..5682c838e53 100644 --- a/mysql-test/suite/merge/merge.result +++ b/mysql-test/suite/merge/merge.result @@ -4022,4 +4022,32 @@ UPDATE v1 SET a=0; DROP VIEW v1; DROP TABLE t1; # End of 11.1 tests +# +# MDEV-38474 Double free or corruption, ASAN heap-use-after-free in st_join_table::cleanup +# +# Test case 1, fails on 10.11+ +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +# Inserts are optional, fails with and without data +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (3),(4); +INSERT INTO t3 VALUES (5),(6); +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE a IN ((SELECT c FROM t3 WHERE FALSE HAVING c < 0))); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +3 MATERIALIZED NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +DROP TABLE t1, t2, t3; +# Test case 2, fails on 11.4 but not on 10.11 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +CREATE TABLE t4 (d INT PRIMARY KEY); +SET SQL_SAFE_UPDATES=1; +UPDATE t1 STRAIGHT_JOIN t2 SET a = 89 WHERE 9 IN (SELECT c FROM t3 WHERE c IN (SELECT MAX(d) FROM t4)); +ERROR HY000: You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column +DROP TABLE t1, t2, t3, t4; +# +# End of 11.4 tests +# ALTER DATABASE test CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci; diff --git a/mysql-test/suite/merge/merge.test b/mysql-test/suite/merge/merge.test index 42f510d4d1a..5cdc08bfef3 100644 --- a/mysql-test/suite/merge/merge.test +++ b/mysql-test/suite/merge/merge.test @@ -2949,4 +2949,39 @@ DROP VIEW v1; DROP TABLE t1; --echo # End of 11.1 tests + +--echo # +--echo # MDEV-38474 Double free or corruption, ASAN heap-use-after-free in st_join_table::cleanup +--echo # + +--echo # Test case 1, fails on 10.11+ +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); + +--echo # Inserts are optional, fails with and without data +INSERT INTO t1 VALUES (1),(2); +INSERT INTO t2 VALUES (3),(4); +INSERT INTO t3 VALUES (5),(6); + +EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT b FROM t2 WHERE a IN ((SELECT c FROM t3 WHERE FALSE HAVING c < 0))); + +DROP TABLE t1, t2, t3; + +--echo # Test case 2, fails on 11.4 but not on 10.11 +CREATE TABLE t1 (a INT); +CREATE TABLE t2 (b INT); +CREATE TABLE t3 (c INT); +CREATE TABLE t4 (d INT PRIMARY KEY); + +SET SQL_SAFE_UPDATES=1; +--error ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE +UPDATE t1 STRAIGHT_JOIN t2 SET a = 89 WHERE 9 IN (SELECT c FROM t3 WHERE c IN (SELECT MAX(d) FROM t4)); + +DROP TABLE t1, t2, t3, t4; + +--echo # +--echo # End of 11.4 tests +--echo # + --source include/test_db_charset_restore.inc diff --git a/mysql-test/suite/parts/r/partition_alter_innodb.result b/mysql-test/suite/parts/r/partition_alter_innodb.result index 160b896847d..0bd5147623a 100644 --- a/mysql-test/suite/parts/r/partition_alter_innodb.result +++ b/mysql-test/suite/parts/r/partition_alter_innodb.result @@ -77,3 +77,12 @@ ALTER TABLE t1 ADD FULLTEXT(f2); InnoDB 0 transactions not purged DROP TABLE t1; # End of 10.6 tests +# +# MDEV-38948 Assertion `time.valid(undo->top_undo_no)' fails +# upon ALTER IGNORE on partitioned table +# +CREATE TABLE t1(a INT) ENGINE=InnoDB PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (1,2), PARTITION pdef DEFAULT); +INSERT INTO t1 VALUES (1),(6); +ALTER IGNORE TABLE t1 FORCE, ALGORITHM=COPY; +DROP TABLE t1; diff --git a/mysql-test/suite/parts/t/partition_alter_innodb.test b/mysql-test/suite/parts/t/partition_alter_innodb.test index dcc448631dc..6e2d74dc35f 100644 --- a/mysql-test/suite/parts/t/partition_alter_innodb.test +++ b/mysql-test/suite/parts/t/partition_alter_innodb.test @@ -18,3 +18,13 @@ ALTER TABLE t1 ADD FULLTEXT(f2); --source ../innodb/include/wait_all_purged.inc DROP TABLE t1; --echo # End of 10.6 tests + +--echo # +--echo # MDEV-38948 Assertion `time.valid(undo->top_undo_no)' fails +--echo # upon ALTER IGNORE on partitioned table +--echo # +CREATE TABLE t1(a INT) ENGINE=InnoDB PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (1,2), PARTITION pdef DEFAULT); +INSERT INTO t1 VALUES (1),(6); +ALTER IGNORE TABLE t1 FORCE, ALGORITHM=COPY; +DROP TABLE t1; diff --git a/mysql-test/suite/perfschema/r/sxlock_func.result b/mysql-test/suite/perfschema/r/sxlock_func.result index d6bbce28ee1..ff556c1e011 100644 --- a/mysql-test/suite/perfschema/r/sxlock_func.result +++ b/mysql-test/suite/perfschema/r/sxlock_func.result @@ -10,7 +10,6 @@ name wait/synch/rwlock/innodb/dict_operation_lock wait/synch/rwlock/innodb/fil_space_latch wait/synch/rwlock/innodb/lock_latch -wait/synch/rwlock/innodb/log_latch wait/synch/rwlock/innodb/trx_i_s_cache_lock wait/synch/rwlock/innodb/trx_purge_latch wait/synch/rwlock/innodb/trx_rseg_latch @@ -44,7 +43,6 @@ ORDER BY event_name; event_name wait/synch/rwlock/innodb/fil_space_latch wait/synch/rwlock/innodb/lock_latch -wait/synch/rwlock/innodb/log_latch SELECT event_name FROM performance_schema.events_waits_history_long WHERE event_name = 'wait/synch/sxlock/innodb/index_tree_rw_lock' AND operation IN ('try_shared_lock','shared_lock') LIMIT 1; diff --git a/mysql-test/suite/perfschema/r/threads_mysql.result b/mysql-test/suite/perfschema/r/threads_mysql.result index ede4ec51d0c..0e4ea20df68 100644 --- a/mysql-test/suite/perfschema/r/threads_mysql.result +++ b/mysql-test/suite/perfschema/r/threads_mysql.result @@ -60,6 +60,17 @@ connection_type NULL unified_parent_thread_id unified parent_thread_id role NULL instrumented YES +name thread/sql/slave_deadlock_handler +type BACKGROUND +processlist_user NULL +processlist_host NULL +processlist_db NULL +processlist_command NULL +processlist_info NULL +connection_type NULL +unified_parent_thread_id unified parent_thread_id +role NULL +instrumented YES CREATE TEMPORARY TABLE t1 AS SELECT thread_id FROM performance_schema.threads WHERE name LIKE 'thread/sql%'; @@ -123,4 +134,5 @@ thread/sql/event_scheduler thread/sql/event_worker thread/sql/main thread/sql/manager thread/sql/main thread/sql/one_connection thread/sql/main thread/sql/signal_handler +thread/sql/main thread/sql/slave_deadlock_handler thread/sql/one_connection thread/sql/event_scheduler diff --git a/mysql-test/suite/rpl/include/check_slave_skip_errors.inc b/mysql-test/suite/rpl/include/check_slave_skip_errors.inc new file mode 100644 index 00000000000..57dfb49186a --- /dev/null +++ b/mysql-test/suite/rpl/include/check_slave_skip_errors.inc @@ -0,0 +1,23 @@ +# ==== Purpose ==== +# +# MDEV-38624: Verify that ER_CONNECTION_KILLED (1927) cannot be added to +# --slave-skip-errors, even when explicitly specified or when using "all". +# +# Called from tests that configure --slave-skip-errors with 1927 or "all". +# Checks that 1927 is absent from slave_skip_errors and that the expected +# warning appears in the slave error log. + +--connection slave +call mtr.add_suppression("Slave: ER_CONNECTION_KILLED .* is not allowed in --slave-skip-errors"); + +--let $skip_errors= query_get_value(SHOW VARIABLES LIKE 'slave_skip_errors', Value, 1) +if (`SELECT '$skip_errors' LIKE '%1927%'`) +{ + --die MDEV-38624: Error 1927 must not be added to slave_skip_errors +} + +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.2.err +--let $assert_select= ER_CONNECTION_KILLED .* is not allowed in --slave-skip-errors +--let $assert_count= 1 +--let $assert_text= Warning about ER_CONNECTION_KILLED should appear in error log +--source include/assert_grep.inc diff --git a/mysql-test/suite/rpl/r/rpl_change_master_implicit_gtid_warning.result b/mysql-test/suite/rpl/r/rpl_change_master_implicit_gtid_warning.result new file mode 100644 index 00000000000..9692bffced2 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_change_master_implicit_gtid_warning.result @@ -0,0 +1,36 @@ +include/master-slave.inc +[connection master] +connection slave; +include/stop_slave.inc +# +# Test 1: CHANGE MASTER TO with relay_log_pos when Using_Gtid is +# already No should NOT produce a spurious 'from No to No' warning +# +CHANGE MASTER TO MASTER_USE_GTID=NO; +CHANGE MASTER TO relay_log_pos=0; +SHOW WARNINGS; +Level Code Message +# +# Test 2: CHANGE MASTER TO with master_log_file/pos when Using_Gtid +# is already No should NOT produce a warning +# +CHANGE MASTER TO master_log_pos=IO_LOG_POS, master_log_file='IO_LOG_FILE'; +SHOW WARNINGS; +Level Code Message +# +# Test 3: CHANGE MASTER TO with log coordinates when Using_Gtid is +# Slave_Pos SHOULD produce a warning (value actually changes) +# +CHANGE MASTER TO MASTER_USE_GTID=Slave_Pos; +CHANGE MASTER TO master_log_pos=IO_LOG_POS, master_log_file='IO_LOG_FILE'; +Warnings: +Note 4190 CHANGE MASTER TO is implicitly changing the value of 'Using_Gtid' from 'Slave_Pos' to 'No' +SHOW WARNINGS; +Level Code Message +Note 4190 CHANGE MASTER TO is implicitly changing the value of 'Using_Gtid' from 'Slave_Pos' to 'No' +# +# Cleanup +# +CHANGE MASTER TO MASTER_USE_GTID=Slave_Pos; +include/start_slave.inc +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_from_mysql80.result b/mysql-test/suite/rpl/r/rpl_from_mysql80.result index 1fac65adbad..0f67f8a6235 100644 --- a/mysql-test/suite/rpl/r/rpl_from_mysql80.result +++ b/mysql-test/suite/rpl/r/rpl_from_mysql80.result @@ -22,8 +22,6 @@ include/wait_for_slave_sql_error.inc [errno=1594] STOP SLAVE IO_THREAD; include/wait_for_slave_io_to_stop.inc CHANGE MASTER TO Master_log_file='master-bin.000001', Master_log_pos=2297; -Warnings: -Note 4190 CHANGE MASTER TO is implicitly changing the value of 'Using_Gtid' from 'No' to 'No' START SLAVE IO_THREAD; START SLAVE SQL_THREAD; include/wait_for_slave_io_to_start.inc @@ -41,8 +39,6 @@ a b STOP SLAVE IO_THREAD; include/wait_for_slave_io_to_stop.inc CHANGE MASTER TO Master_log_file='master-bin.000002', Master_log_pos=4; -Warnings: -Note 4190 CHANGE MASTER TO is implicitly changing the value of 'Using_Gtid' from 'No' to 'No' START SLAVE IO_THREAD; START SLAVE SQL_THREAD; include/wait_for_slave_io_to_start.inc diff --git a/mysql-test/suite/rpl/r/rpl_gtid_excess_initial_delay.result b/mysql-test/suite/rpl/r/rpl_gtid_excess_initial_delay.result index 54098c6056c..2e6afbac545 100644 --- a/mysql-test/suite/rpl/r/rpl_gtid_excess_initial_delay.result +++ b/mysql-test/suite/rpl/r/rpl_gtid_excess_initial_delay.result @@ -5,6 +5,8 @@ connection slave; include/stop_slave.inc CHANGE MASTER TO MASTER_DELAY= 10; include/start_slave.inc +SQL_Remaining_Delay = 'NULL' +Slave_SQL_Running_State = 'Slave has read all relay log; waiting for more updates' connection master; INSERT INTO t1 VALUES (1); include/sync_slave_io_with_master.inc diff --git a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result index 609bc6525d9..f335d3ab732 100644 --- a/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result +++ b/mysql-test/suite/rpl/r/rpl_heartbeat_basic.result @@ -183,6 +183,18 @@ CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER=' ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '''' at line 1 RESET SLAVE; +*** MDEV-38454: MASTER_HEARTBEAT_PERIOD should accept + sign *** +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=+60; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 60.000 +RESET SLAVE; +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=60; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +Variable_name Value +Slave_heartbeat_period 60.000 +RESET SLAVE; + *** Running slave *** CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.1; include/start_slave.inc diff --git a/mysql-test/suite/rpl/r/rpl_mdev38731.result b/mysql-test/suite/rpl/r/rpl_mdev38731.result new file mode 100644 index 00000000000..d099b7af73a --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mdev38731.result @@ -0,0 +1,20 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t (a int, b int, c int, d int, KEY (d)) ENGINE=InnoDB; +INSERT INTO t (a,b,d) VALUES +(1,NULL,4),(2,NULL,1),(3,NULL,1), +(4,NULL,1),(5,NULL,1),(6,NULL,1), +(7,0,NULL),(8,NULL,NULL); +ALTER TABLE t ADD UNIQUE (b); +connection slave; +ANALYZE TABLE t; +Table Op Msg_type Msg_text +test.t analyze status Engine-independent statistics collected +test.t analyze status OK +connection master; +UPDATE t SET c = 1; +ALTER TABLE t ADD UNIQUE (a); +connection slave; +connection master; +DROP TABLE t; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_mdev38734.result b/mysql-test/suite/rpl/r/rpl_mdev38734.result new file mode 100644 index 00000000000..8964331f37d --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_mdev38734.result @@ -0,0 +1,17 @@ +include/master-slave.inc +[connection master] +connection slave; +SET @row_image_save = @@global.binlog_row_image; +SET GLOBAL binlog_row_image=MINIMAL; +include/stop_slave.inc +include/start_slave.inc +connection master; +SET binlog_row_image=MINIMAL; +CREATE TABLE t (pk int primary key, a text, b text, unique(b)); +INSERT INTO t VALUES (1,'foo', 'bar'); +UPDATE t SET a = 'baz'; +connection slave; +SET GLOBAL binlog_row_image = @row_image_save; +connection master; +DROP TABLE t; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result b/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result index 151a00a514b..d4f7f3d9822 100644 --- a/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result +++ b/mysql-test/suite/rpl/r/rpl_read_old_relay_log_info.result @@ -12,4 +12,11 @@ START SLAVE IO_THREAD; include/wait_for_slave_io_to_start.inc # Check that relay log coordinates are equal to those we saved in old-format_relay-log.info = , 0, slave-relay-bin.000001, 4 +# +# MDEV-38020: Master & relay log info files read 2^31 and above incorrectly +# +connection server_2; +include/stop_slave.inc +include/rpl_restart_server.inc [server_number=2 parameters: --skip-slave-start] +include/assert.inc [relay_log_pos should be 2147483648 after restart] include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result index 060fde3b54d..3c89d581512 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_error.result +++ b/mysql-test/suite/rpl/r/rpl_skip_error.result @@ -1,6 +1,9 @@ include/master-slave.inc [connection master] connection slave; +call mtr.add_suppression("Slave: ER_CONNECTION_KILLED .* is not allowed in --slave-skip-errors"); +include/assert_grep.inc [Warning about ER_CONNECTION_KILLED should appear in error log] +connection slave; connection master; ==== Test Without sql_mode=strict_trans_tables ==== create table t1 (n int not null primary key); diff --git a/mysql-test/suite/rpl/r/rpl_temporary_error2_skip_all.result b/mysql-test/suite/rpl/r/rpl_temporary_error2_skip_all.result index 9819aafa5cf..7eaee78df02 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary_error2_skip_all.result +++ b/mysql-test/suite/rpl/r/rpl_temporary_error2_skip_all.result @@ -1,5 +1,8 @@ include/master-slave.inc [connection master] +connection slave; +call mtr.add_suppression("Slave: ER_CONNECTION_KILLED .* is not allowed in --slave-skip-errors"); +include/assert_grep.inc [Warning about ER_CONNECTION_KILLED should appear in error log] call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); *** Provoke a deadlock on the slave, check that transaction retry succeeds. *** connection master; diff --git a/mysql-test/suite/rpl/t/rpl_change_master_implicit_gtid_warning.test b/mysql-test/suite/rpl/t/rpl_change_master_implicit_gtid_warning.test new file mode 100644 index 00000000000..898c1ed32c7 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_change_master_implicit_gtid_warning.test @@ -0,0 +1,52 @@ +# +# Purpose: +# This test validates that CHANGE MASTER TO does not emit a spurious +# warning about implicitly changing Using_Gtid when the value is not +# actually changing. +# +# References: +# MDEV-37842: CHANGE MASTER TO is implicitly changing the value of +# 'Using_Gtid' from 'No' to 'No' +# + +# Format independent test so just use one +--source include/have_binlog_format_mixed.inc +--source include/master-slave.inc + +--connection slave +--source include/stop_slave.inc + +--echo # +--echo # Test 1: CHANGE MASTER TO with relay_log_pos when Using_Gtid is +--echo # already No should NOT produce a spurious 'from No to No' warning +--echo # +CHANGE MASTER TO MASTER_USE_GTID=NO; +CHANGE MASTER TO relay_log_pos=0; +SHOW WARNINGS; + +--echo # +--echo # Test 2: CHANGE MASTER TO with master_log_file/pos when Using_Gtid +--echo # is already No should NOT produce a warning +--echo # +--let $io_log_pos= query_get_value('SHOW SLAVE STATUS', Read_Master_Log_Pos, 1) +--let $io_log_file= query_get_value('SHOW SLAVE STATUS', Master_Log_File, 1) +--replace_result $io_log_file IO_LOG_FILE $io_log_pos IO_LOG_POS +--eval CHANGE MASTER TO master_log_pos=$io_log_pos, master_log_file='$io_log_file' +SHOW WARNINGS; + +--echo # +--echo # Test 3: CHANGE MASTER TO with log coordinates when Using_Gtid is +--echo # Slave_Pos SHOULD produce a warning (value actually changes) +--echo # +CHANGE MASTER TO MASTER_USE_GTID=Slave_Pos; +--replace_result $io_log_file IO_LOG_FILE $io_log_pos IO_LOG_POS +--eval CHANGE MASTER TO master_log_pos=$io_log_pos, master_log_file='$io_log_file' +SHOW WARNINGS; + +--echo # +--echo # Cleanup +--echo # +CHANGE MASTER TO MASTER_USE_GTID=Slave_Pos; +--source include/start_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test b/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test index e844a27019e..899af3424f2 100644 --- a/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test +++ b/mysql-test/suite/rpl/t/rpl_gtid_excess_initial_delay.test @@ -8,13 +8,15 @@ # Steps: # 0 - Stop the slave and execute CHANGE MASTER command with # master_delay= 10 -# 1 - On slave introduce a sleep of 15 seconds and check that the +# 1 - Restart the slave and, after a brief moment, assert no ongoing delay. +# 2 - On the slave, introduce a sleep of 15 seconds and check that the # Seconds_Behind_Master is within specified master_delay limit. It should # not be more that "10" seconds. # # ==== References ==== # # MDEV-13895: GTID and Master_Delay causes excessive initial delay +# MDEV-38825: Slave delays when there is "nothing" to replicate --source include/have_binlog_format_mixed.inc --source include/master-slave.inc @@ -26,6 +28,11 @@ CREATE TABLE t1 (i INT); CHANGE MASTER TO MASTER_DELAY= 10; --source include/start_slave.inc +--sleep 3 +# Should be NULL and idle +--let $status_items= SQL_Remaining_Delay, Slave_SQL_Running_State +--source include/show_slave_status.inc + --connection master INSERT INTO t1 VALUES (1); --source include/sync_slave_io_with_master.inc diff --git a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test index ffd40d95f52..9819e7f1c37 100644 --- a/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test +++ b/mysql-test/suite/rpl/t/rpl_heartbeat_basic.test @@ -239,6 +239,22 @@ eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTE RESET SLAVE; --echo +# +# MDEV-38454: MASTER_HEARTBEAT_PERIOD should accept values with + sign +# +--echo *** MDEV-38454: MASTER_HEARTBEAT_PERIOD should accept + sign *** +# Test with + sign (was broken before fix) +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=+60; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +# Test without + sign (should still work) +--replace_result $MASTER_MYPORT MASTER_PORT +eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=60; +SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period'; +RESET SLAVE; +--echo + # # Testing heartbeat # diff --git a/mysql-test/suite/rpl/t/rpl_mdev38731.test b/mysql-test/suite/rpl/t/rpl_mdev38731.test new file mode 100644 index 00000000000..996f4dbce67 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev38731.test @@ -0,0 +1,21 @@ +--source include/have_innodb.inc +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +CREATE TABLE t (a int, b int, c int, d int, KEY (d)) ENGINE=InnoDB; +INSERT INTO t (a,b,d) VALUES + (1,NULL,4),(2,NULL,1),(3,NULL,1), + (4,NULL,1),(5,NULL,1),(6,NULL,1), + (7,0,NULL),(8,NULL,NULL); +ALTER TABLE t ADD UNIQUE (b); +--sync_slave_with_master +ANALYZE TABLE t; +--connection master +UPDATE t SET c = 1; +ALTER TABLE t ADD UNIQUE (a); + +--sync_slave_with_master + +--connection master +DROP TABLE t; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_mdev38734.test b/mysql-test/suite/rpl/t/rpl_mdev38734.test new file mode 100644 index 00000000000..1c025b0bc1d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_mdev38734.test @@ -0,0 +1,21 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +--connection slave +SET @row_image_save = @@global.binlog_row_image; +SET GLOBAL binlog_row_image=MINIMAL; +--source include/stop_slave.inc +--source include/start_slave.inc + +--connection master +SET binlog_row_image=MINIMAL; +CREATE TABLE t (pk int primary key, a text, b text, unique(b)); +INSERT INTO t VALUES (1,'foo', 'bar'); +UPDATE t SET a = 'baz'; + +--sync_slave_with_master +SET GLOBAL binlog_row_image = @row_image_save; + +--connection master +DROP TABLE t; +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test index d2206b5bef7..db910d80c41 100644 --- a/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test +++ b/mysql-test/suite/rpl/t/rpl_read_old_relay_log_info.test @@ -44,5 +44,30 @@ if (`SELECT "$master_file" != "" OR --die log coordinates changed } +--echo # +--echo # MDEV-38020: Master & relay log info files read 2^31 and above incorrectly +--echo # + +--connection server_2 +--source include/stop_slave.inc + +# Create a relay-log.info file with a position value > 2^31 +--let $MYSQLD_DATADIR= `select @@datadir` +--remove_file $MYSQLD_DATADIR/relay-log.info +--write_file $MYSQLD_DATADIR/relay-log.info +./slave-relay-bin.000001 +2147483648 + +0 +EOF + +--let $rpl_server_number= 2 +--let $rpl_server_parameters= --skip-slave-start +--source include/rpl_restart_server.inc + +--let $assert_text= relay_log_pos should be 2147483648 after restart +--let $assert_cond= [SHOW SLAVE STATUS, Relay_Log_Pos, 1] = 2147483648 +--source include/assert.inc + --let $rpl_only_running_threads= 1 --source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_foreign_key_mdl.test b/mysql-test/suite/rpl/t/rpl_row_foreign_key_mdl.test index 0a5725ece39..6717eadabf8 100644 --- a/mysql-test/suite/rpl/t/rpl_row_foreign_key_mdl.test +++ b/mysql-test/suite/rpl/t/rpl_row_foreign_key_mdl.test @@ -8,6 +8,7 @@ # MDEV-25039: MDL BF-BF conflict because of foreign key # source include/have_innodb.inc; +source include/have_perfschema.inc; source include/have_debug_sync.inc; source include/have_binlog_format_row.inc; source include/master-slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt index 208da1fa722..8f184c77e0c 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt @@ -1 +1 @@ ---slave-skip-errors=1062 +--slave-skip-errors=1062,1927 diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test index ee11ce5ac92..8c521c83050 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error.test +++ b/mysql-test/suite/rpl/t/rpl_skip_error.test @@ -26,9 +26,11 @@ # BUG#28839: Errors in strict mode silently stop SQL thread if --slave-skip-errors exists # bug in this test: BUG#30594: rpl.rpl_skip_error is nondeterministic: # BUG#39393: slave-skip-errors does not work when using ROW based replication +# BUG#38624: ER_CONNECTION_KILLED must not be skippable via --slave-skip-errors source include/have_innodb.inc; source include/master-slave.inc; +--source include/check_slave_skip_errors.inc --connection slave let $initial_skipped_error= query_get_value(show global status like "Slave_skipped_errors", Value, 1); diff --git a/mysql-test/suite/rpl/t/rpl_temporary_error2.test b/mysql-test/suite/rpl/t/rpl_temporary_error2.test index 23a84a02760..17e20100eb4 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_error2.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_error2.test @@ -1,6 +1,11 @@ --source include/have_innodb.inc --source include/master-slave.inc +if ($check_mdev_38624) +{ + --source include/check_slave_skip_errors.inc +} + call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); --disable_query_log call mtr.add_suppression("InnoDB: Transaction was aborted due to "); diff --git a/mysql-test/suite/rpl/t/rpl_temporary_error2_skip_all.test b/mysql-test/suite/rpl/t/rpl_temporary_error2_skip_all.test index 6801bf184d5..bb4e79dff64 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_error2_skip_all.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_error2_skip_all.test @@ -1,3 +1,4 @@ --source include/have_binlog_format_row.inc --let $ignored_db_deadlock= 1 +--let $check_mdev_38624= 1 --source rpl_temporary_error2.test diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index e53edd2f7f3..5d349a9e544 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -611,6 +611,17 @@ create sequence s; select next value for s1 from s as s1; ERROR 42S02: Table 'test.s1' doesn't exist drop sequence s; +# +# MDEV-38815 Server crashes in Item_func_nextval::val_int upon update on a view +# +create sequence s; +create table t (a int default(nextval(s))); +create view v as select * from t; +insert into t values (1); +update v set a= default; +drop view v; +drop table t; +drop sequence s; # End of 10.11 tests # # MDEV-28152 Features for sequence diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index b76c7b6dc2d..ea96cf65294 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -339,6 +339,19 @@ create sequence s; select next value for s1 from s as s1; drop sequence s; +--echo # +--echo # MDEV-38815 Server crashes in Item_func_nextval::val_int upon update on a view +--echo # +create sequence s; +create table t (a int default(nextval(s))); +create view v as select * from t; +insert into t values (1); +update v set a= default; + +drop view v; +drop table t; +drop sequence s; + --echo # End of 10.11 tests --echo # diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff index a2b062a5860..a27c230a9a9 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb,32bit.rdiff @@ -1,6 +1,6 @@ --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result -@@ -51,7 +51,7 @@ +@@ -52,7 +52,7 @@ VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT Number of adaptive hash table cells in each partition; 16381 at start defaults to being derived from innodb_buffer_pool_size NUMERIC_MIN_VALUE 16381 @@ -9,7 +9,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -60,7 +60,7 @@ +@@ -61,7 +61,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 8 VARIABLE_SCOPE GLOBAL @@ -18,7 +18,7 @@ VARIABLE_COMMENT Number of InnoDB Adaptive Hash Index Partitions (default 8) NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 512 -@@ -96,7 +96,7 @@ +@@ -97,7 +97,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -27,7 +27,7 @@ VARIABLE_COMMENT The AUTOINC lock modes supported by InnoDB: 0 => Old style AUTOINC locking (for backward compatibility); 1 => New style AUTOINC locking; 2 => No AUTOINC locking (unsafe for SBR) NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 2 -@@ -108,10 +108,10 @@ +@@ -109,10 +109,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -40,7 +40,7 @@ NUMERIC_BLOCK_SIZE 1048576 ENUM_VALUE_LIST NULL READ_ONLY YES -@@ -144,7 +144,7 @@ +@@ -145,7 +145,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 25 VARIABLE_SCOPE GLOBAL @@ -49,7 +49,7 @@ VARIABLE_COMMENT Dump only the hottest N% of each buffer pool, defaults to 25 NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 100 -@@ -216,10 +216,10 @@ +@@ -217,10 +217,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 134217728 VARIABLE_SCOPE GLOBAL @@ -62,7 +62,7 @@ NUMERIC_BLOCK_SIZE 1048576 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -228,11 +228,11 @@ +@@ -229,11 +229,11 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -77,22 +77,7 @@ ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED -@@ -240,11 +240,11 @@ - SESSION_VALUE NULL - DEFAULT_VALUE 0 - VARIABLE_SCOPE GLOBAL --VARIABLE_TYPE BIGINT UNSIGNED -+VARIABLE_TYPE INT UNSIGNED - VARIABLE_COMMENT Maximum innodb_buffer_pool_size - NUMERIC_MIN_VALUE 0 --NUMERIC_MAX_VALUE 18446744073701163008 --NUMERIC_BLOCK_SIZE 8388608 -+NUMERIC_MAX_VALUE 4292870144 -+NUMERIC_BLOCK_SIZE 2097152 - ENUM_VALUE_LIST NULL - READ_ONLY YES - COMMAND_LINE_ARGUMENT REQUIRED -@@ -252,7 +252,7 @@ +@@ -241,7 +241,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -101,7 +86,7 @@ VARIABLE_COMMENT A number that tells how often buffer pool dump status in percentages should be printed. E.g. 10 means that buffer pool dump status is printed when every 10% of number of buffer pool pages are dumped. Default is 0 (only start and end status is printed) NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 100 -@@ -324,7 +324,7 @@ +@@ -313,7 +313,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 5 VARIABLE_SCOPE GLOBAL @@ -110,7 +95,7 @@ VARIABLE_COMMENT If the compression failure rate of a table is greater than this number more padding is added to the pages to reduce the failures. A value of zero implies no padding NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 100 -@@ -348,7 +348,7 @@ +@@ -337,7 +337,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 50 VARIABLE_SCOPE GLOBAL @@ -119,7 +104,7 @@ VARIABLE_COMMENT Percentage of empty space on a data page that can be reserved to make the page compressible NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 75 -@@ -588,7 +588,7 @@ +@@ -577,7 +577,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 600 VARIABLE_SCOPE GLOBAL @@ -128,7 +113,7 @@ VARIABLE_COMMENT Maximum number of seconds that semaphore times out in InnoDB NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 4294967295 -@@ -636,7 +636,7 @@ +@@ -625,7 +625,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 30 VARIABLE_SCOPE GLOBAL @@ -137,7 +122,7 @@ VARIABLE_COMMENT Number of iterations over which the background flushing is averaged NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 1000 -@@ -660,7 +660,7 @@ +@@ -649,7 +649,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -146,7 +131,7 @@ VARIABLE_COMMENT Controls the durability/speed trade-off for commits. Set to 0 (write and flush redo log to disk only once per second), 1 (flush to disk at each commit), 2 (write to log at commit but flush to disk only once per second) or 3 (flush to disk at prepare and at commit, slower and usually redundant). 1 and 3 guarantees that after a crash, committed transactions will not be lost and will be consistent with the binlog and other transactional engines. 2 can get inconsistent and lose transactions if there is a power failure or kernel crash but not if mysqld crashes. 0 has no guarantees in case of crash. 0 and 2 can be faster than 1 or 3 NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 3 -@@ -684,7 +684,7 @@ +@@ -673,7 +673,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1 VARIABLE_SCOPE GLOBAL @@ -155,7 +140,7 @@ VARIABLE_COMMENT Set to 0 (don't flush neighbors from buffer pool), 1 (flush contiguous neighbors from buffer pool) or 2 (flush neighbors from buffer pool), when flushing a block NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 2 -@@ -720,7 +720,7 @@ +@@ -709,7 +709,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -164,7 +149,7 @@ VARIABLE_COMMENT Helps to save your data in case the disk image of the database becomes corrupt. Value 5 can return bogus data, and 6 can permanently corrupt data NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 6 -@@ -744,10 +744,10 @@ +@@ -733,10 +733,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 8000000 VARIABLE_SCOPE GLOBAL @@ -177,7 +162,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -780,7 +780,7 @@ +@@ -769,7 +769,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 84 VARIABLE_SCOPE GLOBAL @@ -186,16 +171,16 @@ VARIABLE_COMMENT InnoDB Fulltext search maximum token size in characters NUMERIC_MIN_VALUE 10 NUMERIC_MAX_VALUE 84 -@@ -792,7 +792,7 @@ +@@ -781,7 +781,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 3 VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_TYPE INT UNSIGNED VARIABLE_COMMENT InnoDB Fulltext search minimum token size in characters - NUMERIC_MIN_VALUE 0 + NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 16 -@@ -804,7 +804,7 @@ +@@ -793,7 +793,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 2000 VARIABLE_SCOPE GLOBAL @@ -204,7 +189,7 @@ VARIABLE_COMMENT InnoDB Fulltext search number of words to optimize for each optimize table call NUMERIC_MIN_VALUE 1000 NUMERIC_MAX_VALUE 10000 -@@ -816,10 +816,10 @@ +@@ -805,10 +805,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 2000000000 VARIABLE_SCOPE GLOBAL @@ -217,7 +202,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -840,7 +840,7 @@ +@@ -829,7 +829,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 2 VARIABLE_SCOPE GLOBAL @@ -226,7 +211,7 @@ VARIABLE_COMMENT InnoDB Fulltext search parallel sort degree, will round up to nearest power of 2 number NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 16 -@@ -852,10 +852,10 @@ +@@ -841,10 +841,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 640000000 VARIABLE_SCOPE GLOBAL @@ -239,7 +224,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -900,7 +900,7 @@ +@@ -889,7 +889,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 200 VARIABLE_SCOPE GLOBAL @@ -248,7 +233,7 @@ VARIABLE_COMMENT Number of IOPs the server can do. Tunes the background IO rate NUMERIC_MIN_VALUE 100 NUMERIC_MAX_VALUE 4294967295 -@@ -912,7 +912,7 @@ +@@ -901,7 +901,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 4294967295 VARIABLE_SCOPE GLOBAL @@ -257,7 +242,7 @@ VARIABLE_COMMENT Limit to which innodb_io_capacity can be inflated NUMERIC_MIN_VALUE 100 NUMERIC_MAX_VALUE 4294967295 -@@ -1044,10 +1044,10 @@ +@@ -1033,10 +1033,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 32 VARIABLE_SCOPE GLOBAL @@ -270,7 +255,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -1056,10 +1056,10 @@ +@@ -1045,10 +1045,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 1536 VARIABLE_SCOPE GLOBAL @@ -283,7 +268,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -1092,10 +1092,10 @@ +@@ -1081,10 +1081,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -296,7 +281,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY NO -@@ -1104,7 +1104,7 @@ +@@ -1093,7 +1093,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -305,7 +290,7 @@ VARIABLE_COMMENT Maximum delay of user threads in micro-seconds NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 10000000 -@@ -1236,10 +1236,10 @@ +@@ -1225,10 +1225,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL @@ -318,7 +303,7 @@ NUMERIC_BLOCK_SIZE 0 ENUM_VALUE_LIST NULL READ_ONLY YES -@@ -1260,7 +1260,7 @@ +@@ -1249,7 +1249,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 16384 VARIABLE_SCOPE GLOBAL @@ -327,7 +312,7 @@ VARIABLE_COMMENT Page size to use for all InnoDB tablespaces NUMERIC_MIN_VALUE 4096 NUMERIC_MAX_VALUE 65536 -@@ -1296,7 +1296,7 @@ +@@ -1285,7 +1285,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 127 VARIABLE_SCOPE GLOBAL @@ -336,7 +321,7 @@ VARIABLE_COMMENT Number of UNDO log pages to purge in one batch from the history list NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 5000 -@@ -1308,7 +1308,7 @@ +@@ -1297,7 +1297,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 128 VARIABLE_SCOPE GLOBAL @@ -345,7 +330,7 @@ VARIABLE_COMMENT Unused NUMERIC_MIN_VALUE 1 NUMERIC_MAX_VALUE 128 -@@ -1344,7 +1344,7 @@ +@@ -1333,7 +1333,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 56 VARIABLE_SCOPE GLOBAL @@ -354,7 +339,7 @@ VARIABLE_COMMENT Number of pages that must be accessed sequentially for InnoDB to trigger a readahead NUMERIC_MIN_VALUE 0 NUMERIC_MAX_VALUE 64 -@@ -1428,7 +1428,7 @@ +@@ -1417,7 +1417,7 @@ SESSION_VALUE NULL DEFAULT_VALUE 1048576 VARIABLE_SCOPE GLOBAL @@ -363,7 +348,7 @@ VARIABLE_COMMENT Memory buffer size for index creation NUMERIC_MIN_VALUE 65536 NUMERIC_MAX_VALUE 67108864 -@@ -1596,10 +1596,10 @@ +@@ -1585,10 +1585,10 @@ SESSION_VALUE NULL DEFAULT_VALUE 30 VARIABLE_SCOPE GLOBAL diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index 36bd5ca6894..7ebab3dc8c7 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -4,6 +4,7 @@ variable_name not in ( 'innodb_numa_interleave', # only available WITH_NUMA 'innodb_evict_tables_on_commit_debug', # one may want to override this 'innodb_use_native_aio', # default value depends on OS +'innodb_buffer_pool_size_max', # default value depends on OS 'innodb_log_file_buffering', # only available on Linux and Windows 'innodb_linux_aio', # existence depends on OS 'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing @@ -248,18 +249,6 @@ NUMERIC_BLOCK_SIZE 8388608 ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED -VARIABLE_NAME INNODB_BUFFER_POOL_SIZE_MAX -SESSION_VALUE NULL -DEFAULT_VALUE 0 -VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BIGINT UNSIGNED -VARIABLE_COMMENT Maximum innodb_buffer_pool_size -NUMERIC_MIN_VALUE 0 -NUMERIC_MAX_VALUE 18446744073701163008 -NUMERIC_BLOCK_SIZE 8388608 -ENUM_VALUE_LIST NULL -READ_ONLY YES -COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_BUF_DUMP_STATUS_FREQUENCY SESSION_VALUE NULL DEFAULT_VALUE 0 diff --git a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result index 68c94dcd11d..9a756da07bc 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_wsrep.result +++ b/mysql-test/suite/sys_vars/r/sysvars_wsrep.result @@ -563,7 +563,7 @@ GLOBAL_VALUE_ORIGIN COMPILE-TIME DEFAULT_VALUE ON VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Should slave thread do foreign key constraint checks +VARIABLE_COMMENT Should slave thread do foreign key constraint checks (deprecated, has no effect) NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result index 40b3270e221..ad6b77c9df6 100644 --- a/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result +++ b/mysql-test/suite/sys_vars/r/wsrep_slave_fk_checks_basic.result @@ -12,24 +12,34 @@ SELECT @@global.wsrep_slave_fk_checks; SELECT @@session.wsrep_slave_fk_checks; ERROR HY000: Variable 'wsrep_slave_FK_checks' is a GLOBAL variable SET @@global.wsrep_slave_fk_checks=OFF; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release SELECT @@global.wsrep_slave_fk_checks; @@global.wsrep_slave_fk_checks 0 SET @@global.wsrep_slave_fk_checks=ON; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release SELECT @@global.wsrep_slave_fk_checks; @@global.wsrep_slave_fk_checks 1 # valid values SET @@global.wsrep_slave_fk_checks='OFF'; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release SELECT @@global.wsrep_slave_fk_checks; @@global.wsrep_slave_fk_checks 0 SET @@global.wsrep_slave_fk_checks=ON; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release SELECT @@global.wsrep_slave_fk_checks; @@global.wsrep_slave_fk_checks 1 SET @@global.wsrep_slave_fk_checks=default; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release SELECT @@global.wsrep_slave_fk_checks; @@global.wsrep_slave_fk_checks 1 @@ -42,4 +52,6 @@ ERROR 42000: Variable 'wsrep_slave_FK_checks' can't be set to the value of 'junk # restore the initial value SET @@global.wsrep_slave_fk_checks = @wsrep_slave_fk_checks_global_saved; +Warnings: +Warning 1287 '@@wsrep_slave_FK_checks' is deprecated and will be removed in a future release # End of test diff --git a/mysql-test/suite/sys_vars/t/sysvars_innodb.test b/mysql-test/suite/sys_vars/t/sysvars_innodb.test index 250eb8b5c8f..a47691a7af6 100644 --- a/mysql-test/suite/sys_vars/t/sysvars_innodb.test +++ b/mysql-test/suite/sys_vars/t/sysvars_innodb.test @@ -15,6 +15,7 @@ select VARIABLE_NAME, SESSION_VALUE, DEFAULT_VALUE, VARIABLE_SCOPE, VARIABLE_TYP 'innodb_numa_interleave', # only available WITH_NUMA 'innodb_evict_tables_on_commit_debug', # one may want to override this 'innodb_use_native_aio', # default value depends on OS + 'innodb_buffer_pool_size_max', # default value depends on OS 'innodb_log_file_buffering', # only available on Linux and Windows 'innodb_linux_aio', # existence depends on OS 'innodb_buffer_pool_load_pages_abort') # debug build only, and is only for testing diff --git a/mysql-test/suite/sysschema/r/pr_ps_setup_show_enabled.result b/mysql-test/suite/sysschema/r/pr_ps_setup_show_enabled.result index 631a13bb649..afbbd614ee1 100644 --- a/mysql-test/suite/sysschema/r/pr_ps_setup_show_enabled.result +++ b/mysql-test/suite/sysschema/r/pr_ps_setup_show_enabled.result @@ -211,6 +211,7 @@ mysys/statement_timer BACKGROUND root@localhost FOREGROUND sql/main BACKGROUND sql/manager BACKGROUND +sql/slave_deadlock_handler BACKGROUND CALL sys.ps_setup_show_enabled(TRUE, TRUE); performance_schema_enabled 1 @@ -242,6 +243,7 @@ mysys/statement_timer BACKGROUND root@localhost FOREGROUND sql/main BACKGROUND sql/manager BACKGROUND +sql/slave_deadlock_handler BACKGROUND enabled_instruments timed idle YES memory/performance_schema/accounts NO diff --git a/mysql-test/suite/wsrep/r/wsrep_provider_plugin_defaults.result b/mysql-test/suite/wsrep/r/wsrep_provider_plugin_defaults.result index 77c36da1af6..547164d266f 100644 --- a/mysql-test/suite/wsrep/r/wsrep_provider_plugin_defaults.result +++ b/mysql-test/suite/wsrep/r/wsrep_provider_plugin_defaults.result @@ -89,16 +89,16 @@ COMMAND_LINE_ARGUMENT REQUIRED GLOBAL_VALUE_PATH NULL VARIABLE_NAME WSREP_PROVIDER_EVS_AUTO_EVICT SESSION_VALUE NULL -GLOBAL_VALUE OFF +GLOBAL_VALUE 0 GLOBAL_VALUE_ORIGIN COMPILE-TIME -DEFAULT_VALUE OFF +DEFAULT_VALUE 0 VARIABLE_SCOPE GLOBAL -VARIABLE_TYPE BOOLEAN +VARIABLE_TYPE BIGINT VARIABLE_COMMENT Wsrep provider option -NUMERIC_MIN_VALUE NULL -NUMERIC_MAX_VALUE NULL -NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST OFF,ON +NUMERIC_MIN_VALUE -9223372036854775808 +NUMERIC_MAX_VALUE 9223372036854775807 +NUMERIC_BLOCK_SIZE 0 +ENUM_VALUE_LIST NULL READ_ONLY YES COMMAND_LINE_ARGUMENT REQUIRED GLOBAL_VALUE_PATH NULL diff --git a/mysql-test/suite/wsrep/t/wsrep_provider_plugin.test b/mysql-test/suite/wsrep/t/wsrep_provider_plugin.test index 453e5bb0dae..de4533f879c 100644 --- a/mysql-test/suite/wsrep/t/wsrep_provider_plugin.test +++ b/mysql-test/suite/wsrep/t/wsrep_provider_plugin.test @@ -6,7 +6,7 @@ --source include/have_wsrep.inc --source include/have_innodb.inc ---let $galera_version=26.4.14 +--let $galera_version=26.4.26 source include/check_galera_version.inc; CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB; diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 8f1b3f406de..953fb573659 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -86,7 +86,7 @@ int my_copy(const char *from, const char *to, myf MyFlags) file_created= 1; while ((Count=my_read(from_file, buff, sizeof(buff), MyFlags)) != 0) { - if (Count == (uint) -1 || + if (Count == MY_FILE_ERROR || my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP))) goto err; } diff --git a/mysys/my_file.c b/mysys/my_file.c index c2b358f5e1e..3c065c0ab44 100644 --- a/mysys/my_file.c +++ b/mysys/my_file.c @@ -50,23 +50,37 @@ static uint set_max_open_files(uint max_file_limit) { old_cur= (uint) rlimit.rlim_cur; DBUG_PRINT("info", ("rlim_cur: %u rlim_max: %u", - (uint) rlimit.rlim_cur, - (uint) rlimit.rlim_max)); + (uint) rlimit.rlim_cur, + (uint) rlimit.rlim_max)); if ((ulonglong) rlimit.rlim_cur == (ulonglong) RLIM_INFINITY || rlimit.rlim_cur >= max_file_limit) DBUG_RETURN(max_file_limit); - rlimit.rlim_cur= rlimit.rlim_max= max_file_limit; - if (setrlimit(RLIMIT_NOFILE, &rlimit)) + + /* Never lower the hard limit (rlim_max): lowering is irreversible for + non-privileged users and can prevent later increases. */ + if ((ulonglong) rlimit.rlim_max != (ulonglong) RLIM_INFINITY && + max_file_limit > rlimit.rlim_max) + { + /* Best effort: try raising hard limit only when needed. */ + rlimit.rlim_max= max_file_limit; + } + + /* Soft limit cannot exceed hard limit. */ + rlimit.rlim_cur= max_file_limit; + + if (setrlimit(RLIMIT_NOFILE, &rlimit)) { max_file_limit= old_cur; /* Use original value */ + } else { rlimit.rlim_cur= 0; /* Safety if next call fails */ (void) getrlimit(RLIMIT_NOFILE,&rlimit); DBUG_PRINT("info", ("rlim_cur: %u", (uint) rlimit.rlim_cur)); if (rlimit.rlim_cur) /* If call didn't fail */ - max_file_limit= (uint) rlimit.rlim_cur; + max_file_limit= (uint) rlimit.rlim_cur; } } + DBUG_PRINT("exit",("max_file_limit: %u", max_file_limit)); DBUG_RETURN(max_file_limit); } diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 8952cc8c310..0a6bf530c49 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -822,7 +822,7 @@ static int setval(const struct my_option *opts, void *value, char *argument, *((long*) value)= (long) getopt_ll(argument, opts, &err); break; case GET_ULONG: - *((long*) value)= (long) getopt_ull(argument, opts, &err); + *((ulong*) value)= (ulong) getopt_ull(argument, opts, &err); break; case GET_LL: *((longlong*) value)= getopt_ll(argument, opts, &err); diff --git a/mysys/my_largepage.c b/mysys/my_largepage.c index 665c3ad04c8..5d864ad7c27 100644 --- a/mysys/my_largepage.c +++ b/mysys/my_largepage.c @@ -482,13 +482,21 @@ char *my_large_virtual_alloc(size_t *size) DBUG_RETURN(ptr); } } + + my_use_large_pages= FALSE; } +# ifdef _AIX + /* On IBM AIX, my_virtual_mem_commit() relies on mprotect(2) rather than + a subsequent mmap(2) with MAP_FIXED. */ ptr= mmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_PRIVATE | OS_MAP_ANON, -1, 0); +# else + ptr= mmap(NULL, *size, PROT_NONE, MAP_PRIVATE | OS_MAP_ANON, -1, 0); +# endif if (ptr == MAP_FAILED) { - my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), size); + my_error(EE_OUTOFMEMORY, MYF(ME_BELL + ME_ERROR_LOG), *size); ptr= NULL; } diff --git a/mysys/my_virtual_mem.c b/mysys/my_virtual_mem.c index 649d8c693ff..7157dd7ae06 100644 --- a/mysys/my_virtual_mem.c +++ b/mysys/my_virtual_mem.c @@ -103,9 +103,6 @@ char *my_virtual_mem_commit(char *ptr, size_t size) # else void *p= 0; const int flags= -# ifdef MAP_POPULATE - MAP_POPULATE | -# endif MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; p= mmap(ptr, size, PROT_READ | PROT_WRITE, flags, -1, 0); if (p == MAP_FAILED) @@ -128,9 +125,6 @@ void my_virtual_mem_decommit(char *ptr, size_t size) { #ifdef _WIN32 DBUG_ASSERT(is_memory_committed(ptr, size)); -# ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT -# error "VirtualFree(MEM_DECOMMIT) will not allow subsequent reads!" -# endif if (!my_use_large_pages) { if (!VirtualFree(ptr, size, MEM_DECOMMIT)) @@ -141,19 +135,6 @@ void my_virtual_mem_decommit(char *ptr, size_t size) } } #else - const int prot= -# ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT - /* - In InnoDB, buf_pool_t::page_guess() may deference pointers to - this, assuming that either the original contents or zeroed - contents is available. - */ - PROT_READ -# else - /* We will explicitly mark the memory unaccessible. */ - PROT_NONE -# endif - ; # ifdef _AIX disclaim(ptr, size, DISCLAIM_ZEROMEM); # elif defined __linux__ || defined __osf__ @@ -172,7 +153,7 @@ void my_virtual_mem_decommit(char *ptr, size_t size) # else # warning "Do not know how to decommit memory" # endif - if (mprotect(ptr, size, prot)) + if (mprotect(ptr, size, PROT_NONE)) { my_error(EE_BADMEMORYRELEASE, MYF(ME_ERROR_LOG_ONLY), ptr, size, errno); DBUG_ASSERT(0); diff --git a/scripts/mariadb_system_tables_fix.sql b/scripts/mariadb_system_tables_fix.sql index eb60d3e904d..4ef24a191b1 100644 --- a/scripts/mariadb_system_tables_fix.sql +++ b/scripts/mariadb_system_tables_fix.sql @@ -892,7 +892,20 @@ IF 'BASE TABLE' = (select table_type from information_schema.tables where table_ DROP TABLE user; END IF// -IF 1 = (SELECT count(*) FROM information_schema.VIEWS WHERE TABLE_CATALOG = 'def' and TABLE_SCHEMA = 'mysql' and TABLE_NAME='user' and (DEFINER = 'root@localhost' or (DEFINER = 'mariadb.sys@localhost' and VIEW_DEFINITION LIKE "%'N' AS `password_expired`%"))) THEN +IF 1 = (SELECT count(*) FROM information_schema.VIEWS + WHERE TABLE_CATALOG = 'def' + AND TABLE_SCHEMA = 'mysql' + AND TABLE_NAME = 'user' + AND (DEFINER = 'root@localhost' + OR (DEFINER = 'mariadb.sys@localhost' + AND (VIEW_DEFINITION LIKE "%'N' AS `password_expired`%" + OR CHARACTER_SET_CLIENT <> 'latin1' + OR COLLATION_CONNECTION <> 'latin1_swedish_ci' + ) + ) + ) + ) +THEN DROP VIEW IF EXISTS mysql.user; END IF// diff --git a/sql/gcalc_slicescan.cc b/sql/gcalc_slicescan.cc index 2bc8bc3f410..63c855bcadb 100644 --- a/sql/gcalc_slicescan.cc +++ b/sql/gcalc_slicescan.cc @@ -900,14 +900,18 @@ static Gcalc_heap::Info *new_eq_point( } -void Gcalc_heap::Info::calc_xy(double *x, double *y) const +void Gcalc_heap::Info::calc_intersection_xy(double *x, double *y) const { + GCALC_DBUG_ASSERT(type == nt_intersection); double b0_x= node.intersection.p2->node.shape.x - node.intersection.p1->node.shape.x; double b0_y= node.intersection.p2->node.shape.y - node.intersection.p1->node.shape.y; double b1_x= node.intersection.p4->node.shape.x - node.intersection.p3->node.shape.x; double b1_y= node.intersection.p4->node.shape.y - node.intersection.p3->node.shape.y; double b0xb1= b0_x * b1_y - b0_y * b1_x; - double t= (node.intersection.p3->node.shape.x - node.intersection.p1->node.shape.x) * b1_y - (node.intersection.p3->node.shape.y - node.intersection.p1->node.shape.y) * b1_x; + double t=(node.intersection.p3->node.shape.x - + node.intersection.p1->node.shape.x) * b1_y - + (node.intersection.p3->node.shape.y - + node.intersection.p1->node.shape.y) * b1_x; t/= b0xb1; @@ -916,6 +920,19 @@ void Gcalc_heap::Info::calc_xy(double *x, double *y) const } +void Gcalc_heap::Info::get_xy(double *x, double *y) const +{ + if (type == nt_intersection) + calc_intersection_xy(x, y); + else + { + GCALC_DBUG_ASSERT(type == nt_shape_node); + *x= node.shape.x; + *y= node.shape.y; + } +} + + #ifdef GCALC_CHECK_WITH_FLOAT void Gcalc_heap::Info::calc_xy_ld(long double *x, long double *y) const { @@ -1923,7 +1940,8 @@ double Gcalc_scan_iterator::get_y() const Gcalc_coord2 t_a, t_b; Gcalc_coord3 a_tb, b_ta, y_exp; calc_t(t_a, t_b, dxa, dya, - state.pi->node.intersection.p1, state.pi->node.intersection.p2, state.pi->node.intersection.p3, state.pi->node.intersection.p4); + state.pi->node.intersection.p1, state.pi->node.intersection.p2, + state.pi->node.intersection.p3, state.pi->node.intersection.p4); gcalc_mul_coord(a_tb, GCALC_COORD_BASE3, @@ -1969,14 +1987,12 @@ double Gcalc_scan_iterator::get_event_x() const double Gcalc_scan_iterator::get_h() const { double cur_y= get_y(); - double next_y; - if (state.pi->type == Gcalc_heap::nt_intersection) - { - double x; - state.pi->calc_xy(&x, &next_y); - } - else - next_y= state.pi->next ? state.pi->get_next()->node.shape.y : 0.0; + double x, next_y; + + GCALC_DBUG_ASSERT(m_cur_pi); + + m_cur_pi->get_xy(&x, &next_y); + return next_y - cur_y; } diff --git a/sql/gcalc_slicescan.h b/sql/gcalc_slicescan.h index e5c2873c696..7a149a194c4 100644 --- a/sql/gcalc_slicescan.h +++ b/sql/gcalc_slicescan.h @@ -216,7 +216,8 @@ public: bool is_single_node() const { return is_bottom() && is_top(); } - void calc_xy(double *x, double *y) const; + void calc_intersection_xy(double *x, double *y) const; + void get_xy(double *x, double *y) const; int equal_pi(const Info *pi) const; #ifdef GCALC_CHECK_WITH_FLOAT void calc_xy_ld(long double *x, long double *y) const; diff --git a/sql/gcalc_tools.cc b/sql/gcalc_tools.cc index 49f611f6496..a95d3325c39 100644 --- a/sql/gcalc_tools.cc +++ b/sql/gcalc_tools.cc @@ -236,7 +236,7 @@ exit: if (result == result_true) { c_op= (c_op & ~v_mask) | v_t_found; - int4store(sav_cur_func, c_op); + int4store(const_cast(sav_cur_func), c_op); } else { @@ -248,7 +248,7 @@ exit: if (result == result_false) { c_op= (c_op & ~v_mask) | v_f_found; - int4store(sav_cur_func, c_op); + int4store(const_cast(sav_cur_func), c_op); } else { @@ -1292,7 +1292,7 @@ inline int Gcalc_operation_reducer::get_single_result(res_point *res, if (res->intersection_point) { double x, y; - res->pi->calc_xy(&x, &y); + res->pi->calc_intersection_xy(&x, &y); if (storage->single_point(x,y)) GCALC_DBUG_RETURN(1); } @@ -1319,7 +1319,7 @@ int Gcalc_operation_reducer::get_result_thread(res_point *cur, { if (cur->intersection_point) { - cur->pi->calc_xy(&x, &y); + cur->pi->calc_intersection_xy(&x, &y); } else { diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index c4c8d0229fe..9cc10b16fda 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -2133,12 +2133,12 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, DBUG_ASSERT(m_new_file == 0); m_new_file= new_file_array; for (i= 0; i < part_count; i++) - m_added_file[i]->extra(HA_EXTRA_BEGIN_ALTER_COPY); + m_added_file[i]->extra(HA_EXTRA_BEGIN_COPY); error= copy_partitions(copied, deleted); for (i= 0; i < part_count; i++) m_added_file[i]->extra(error - ? HA_EXTRA_ABORT_ALTER_COPY - : HA_EXTRA_END_ALTER_COPY); + ? HA_EXTRA_ABORT_COPY + : HA_EXTRA_END_COPY); if (unlikely(error)) { /* @@ -9737,9 +9737,10 @@ int ha_partition::extra(enum ha_extra_function operation) */ DBUG_RETURN(ER_UNSUPORTED_LOG_ENGINE); case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN: - case HA_EXTRA_BEGIN_ALTER_COPY: - case HA_EXTRA_END_ALTER_COPY: - case HA_EXTRA_ABORT_ALTER_COPY: + case HA_EXTRA_BEGIN_COPY: + case HA_EXTRA_END_COPY: + case HA_EXTRA_ABORT_COPY: + case HA_EXTRA_BEGIN_ALTER_IGNORE_COPY: DBUG_RETURN(loop_partitions(extra_cb, &operation)); default: { diff --git a/sql/handler.cc b/sql/handler.cc index 65af1a4b095..abba1047ac7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6090,12 +6090,15 @@ Alter_inplace_info::Alter_inplace_info(HA_CREATE_INFO *create_info_arg, : create_info(create_info_arg), alter_info(alter_info_arg), key_info_buffer(key_info_arg), - key_count(key_count_arg), - rename_keys(current_thd->mem_root), modified_part_info(modified_part_info_arg), - ignore(ignore_arg), + rename_keys(current_thd->mem_root), + key_count(key_count_arg), inplace_supported(HA_ALTER_ERROR), - error_if_not_empty(error_non_empty) + online(false), + file_per_table(false), + ignore(ignore_arg), + error_if_not_empty(error_non_empty), + mdl_exclusive_after_prepare(false) {} void Alter_inplace_info::report_unsupported_error(const char *not_supported, diff --git a/sql/handler.h b/sql/handler.h index c7f93e3767e..354e5d6192d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -2731,21 +2731,12 @@ public: */ KEY *key_info_buffer; - /** Size of key_info_buffer array. */ - uint key_count; - - /** Size of index_drop_buffer array. */ - uint index_drop_count= 0; - /** Array of pointers to KEYs to be dropped belonging to the TABLE instance for the old version of the table. */ KEY **index_drop_buffer= nullptr; - /** Size of index_add_buffer array. */ - uint index_add_count= 0; - /** Array of indexes into key_info_buffer for KEYs to be added, sorted in increasing order. @@ -2754,32 +2745,6 @@ public: KEY_PAIR *index_altered_ignorability_buffer= nullptr; - /** Size of index_altered_ignorability_buffer array. */ - uint index_altered_ignorability_count= 0; - - /** - Old and new index names. Used for index rename. - */ - struct Rename_key_pair - { - Rename_key_pair(const KEY *old_key, const KEY *new_key) - : old_key(old_key), new_key(new_key) - { - } - const KEY *old_key; - const KEY *new_key; - }; - /** - Vector of key pairs from DROP/ADD index which can be renamed. - */ - typedef Mem_root_array Rename_keys_vector; - - /** - A list of indexes which should be renamed. - Index definitions stays the same. - */ - Rename_keys_vector rename_keys; - /** Context information to allow handlers to keep context between in-place alter API calls. @@ -2806,9 +2771,6 @@ public: */ alter_table_operations handler_flags= 0; - /* Alter operations involving partitions are stored here */ - ulong partition_flags; - /** Partition_info taking into account the partition changes to be performed. Contains all partitions which are present in the old version of the table @@ -2817,12 +2779,6 @@ public: */ partition_info * const modified_part_info; - /** true for ALTER IGNORE TABLE ... */ - const bool ignore; - - /** true for online operation (LOCK=NONE) */ - bool online= false; - /** When ha_commit_inplace_alter_table() is called the engine can set this to a function to be called after the ddl log @@ -2834,9 +2790,6 @@ public: /* This will be used as the argument to the above function when called */ void *inplace_alter_table_committed_argument= nullptr; - /** which ALGORITHM and LOCK are supported by the storage engine */ - enum_alter_inplace_result inplace_supported; - /** Can be set by handler to describe why a given operation cannot be done in-place (HA_ALTER_INPLACE_NOT_SUPPORTED) or why it cannot be done @@ -2851,11 +2804,57 @@ public: */ const char *unsupported_reason= nullptr; - /** true when InnoDB should abort the alter when table is not empty */ - const bool error_if_not_empty; + /* Alter operations involving parititons are strored here */ + ulong partition_flags; + /** + Old and new index names. Used for index rename. + */ + struct Rename_key_pair + { + Rename_key_pair(const KEY *old_key, const KEY *new_key) + : old_key(old_key), new_key(new_key) + { + } + const KEY *old_key; + const KEY *new_key; + }; + /** + Vector of key pairs from DROP/ADD index which can be renamed. + */ + typedef Mem_root_array Rename_keys_vector; + + /** + A list of indexes which should be renamed. + Index definitions stays the same. + */ + Rename_keys_vector rename_keys; + + /** Size of key_info_buffer array. */ + uint key_count; + + /** Size of index_drop_buffer array. */ + uint index_drop_count= 0; + + /** Size of index_add_buffer array. */ + uint index_add_count= 0; + + /** Size of index_altered_ignorability_buffer array. */ + uint index_altered_ignorability_count= 0; + + /** which ALGORITHM and LOCK are supported by the storage engine */ + enum_alter_inplace_result inplace_supported; + + /** TRUE for online operation (LOCK=NONE) */ + unsigned online : 1; + /** TRUE when innodb_file_per_table is set */ + unsigned file_per_table : 1; + /** TRUE for ALTER IGNORE TABLE ... */ + unsigned ignore : 1; + /** true when InnoDB should abort the alter when table is not empty */ + unsigned error_if_not_empty : 1; /** True when DDL should avoid downgrading the MDL */ - bool mdl_exclusive_after_prepare= false; + unsigned mdl_exclusive_after_prepare : 1; Alter_inplace_info(HA_CREATE_INFO *create_info_arg, Alter_info *alter_info_arg, diff --git a/sql/item.cc b/sql/item.cc index 7518f12477b..7364b59a80a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9101,7 +9101,7 @@ bool Item_ref::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) bool Item_ref::val_native(THD *thd, Native *to) { - return val_native_from_item(thd, *ref, to); + return val_native_result_from_item(thd, *ref, to); } diff --git a/sql/item.h b/sql/item.h index 8b91ce797b6..21559334c10 100644 --- a/sql/item.h +++ b/sql/item.h @@ -950,6 +950,13 @@ protected: res= NULL; return res; } + bool val_native_result_from_item(THD *thd, Item *item, Native *to) + { + DBUG_ASSERT(fixed()); + null_value= item->val_native_result(thd, to); + DBUG_ASSERT(null_value == item->null_value); + return null_value; + } bool val_native_from_item(THD *thd, Item *item, Native *to) { DBUG_ASSERT(fixed()); @@ -8722,7 +8729,11 @@ public: bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return m_item->excl_dep_on_grouping_fields(sel); } bool is_expensive() override { return m_item->is_expensive(); } - void set_item(Item *item) { m_item= item; } + void set_item(Item *item) + { + m_item= item; + ref= &m_item; + } Item *deep_copy(THD *thd) const override { Item *clone_item= m_item->deep_copy_with_checks(thd); diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index ec2ef5ee6f5..a28b91ad8f8 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -98,7 +98,7 @@ String *Item_func_geometry_from_wkb::val_str(String *str) if (str->copy(*str_ret)) return 0; - int4store(str->ptr(), srid); + int4store(const_cast(str->ptr()), srid); return str; } return str_ret; @@ -1389,6 +1389,8 @@ public: } int store_shapes(Gcalc_shape_transporter *trn) const { return geom->store_shapes(trn); } + int shape_type() const + { return geom->get_class_info()->m_type_id; } }; @@ -1521,6 +1523,16 @@ bool Item_func_spatial_precise_rel::val_bool() Gcalc_function::op_intersection, 2); null_value= g1.store_shapes(&trn) || g2.store_shapes(&trn); break; + case SP_CROSSES_FUNC: + if (g1.shape_type() == Geometry::wkb_polygon || + g1.shape_type() == Geometry::wkb_multipolygon || + g2.shape_type() == Geometry::wkb_point || + g2.shape_type() == Geometry::wkb_multipoint) + { + null_value= true; + goto exit; + } + /* fall through */ case SP_OVERLAPS_FUNC: { // Both geometries must have the same number of dimensions. @@ -1534,10 +1546,6 @@ bool Item_func_spatial_precise_rel::val_bool() shape_a, shape_b, null_value); break; } - case SP_CROSSES_FUNC: - handle_sp_crosses_func_case(func, trn, g1, g2, - shape_a, shape_b, null_value); - break; case SP_TOUCHES_FUNC: if (func.reserve_op_buffer(5)) break; @@ -3334,6 +3342,16 @@ String *Item_func_pointfromgeohash::val_str(String *str) } +static double count_h_x(double x1, double y1, double x2, double y2, double h) +{ + double dy= y2 - y1; + double dx= x2 - x1; + double dh= h - y1; + + return x1 + dx * dh / dy; +} + + String *Item_func_pointonsurface::val_str(String *str) { Gcalc_operation_transporter trn(&func, &collector); @@ -3342,7 +3360,7 @@ String *Item_func_pointonsurface::val_str(String *str) Geometry *g; MBR mbr; const char *c_end; - double UNINIT_VAR(px), UNINIT_VAR(py), x0, UNINIT_VAR(y0); + double UNINIT_VAR(px), UNINIT_VAR(py); String *result= 0; const Gcalc_scan_iterator::point *pprev= NULL; uint32 srid; @@ -3365,54 +3383,54 @@ String *Item_func_pointonsurface::val_str(String *str) while (scan_it.more_points()) { + double h; + if (scan_it.step()) goto mem_error; - if (scan_it.get_h() > GIS_ZERO) - { - y0= scan_it.get_y(); - break; - } - } + if (!scan_it.more_points()) + goto exit; - if (!scan_it.more_points()) - { - goto exit; - } - - if (scan_it.step()) - goto mem_error; - - for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit) - { - if (pprev == NULL) - { - pprev= pit.point(); + if ((h= scan_it.get_h()) <= GIS_ZERO) continue; - } - x0= scan_it.get_sp_x(pprev); - px= scan_it.get_sp_x(pit.point()); - if (px - x0 > GIS_ZERO) + + py= scan_it.get_y() + h/2.0; + + for (Gcalc_point_iterator pit(&scan_it); pit.point(); ++pit) { - if (scan_it.get_h() > GIS_ZERO) + const Gcalc_scan_iterator::point *p= pit.point(); + double x1, y1, x2, y2, xa, xb; + + if (pprev == NULL) { - px= (px + x0) / 2.0; - py= scan_it.get_y(); + pprev= pit.point(); + continue; } - else + + pprev->pi->get_xy(&x1, &y1); + pprev->next_pi->get_xy(&x2, &y2); + + xa= count_h_x(x1, y1, x2, y2, py); + + p->pi->get_xy(&x1, &y1); + p->next_pi->get_xy(&x2, &y2); + xb= count_h_x(x1, y1, x2, y2, py); + + if (xb - xa > GIS_ZERO) { - px= (px + x0) / 2.0; - py= (y0 + scan_it.get_y()) / 2.0; + px= (xa + xb) / 2.0; + null_value= 0; + goto point_found; } - null_value= 0; - break; + + pprev= NULL; } - pprev= NULL; } if (null_value) goto exit; +point_found: str->set_charset(&my_charset_bin); str->length(0); if (str->reserve(SRID_SIZE, 512)) diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 62c003091d4..68bdb7cb080 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -761,7 +761,7 @@ String *Item_func_json_value::val_str(String *to) args[1], collation.collation, &json_depth_array, - &func_name_str); + func_name_str.str, false); return null_value ? NULL : to; } @@ -789,7 +789,7 @@ String *Item_func_json_query::val_str(String *to) args[1], collation.collation, &json_depth_array, - &func_name_str); + func_name_str.str, true); return null_value ? NULL : to; } @@ -807,7 +807,7 @@ bool Json_path_extractor::extract(MEM_ROOT *mem_root, String *str, Item *item_js, Item *item_jp, CHARSET_INFO *cs, MEM_ROOT_DYNAMIC_ARRAY *array_counters, - LEX_CSTRING *func_name_str) + const char *func_name, bool allow_wildcard) { String *js= item_js->val_json(&tmp_js); json_path_step_t *tmp_ptr= NULL; @@ -816,9 +816,29 @@ bool Json_path_extractor::extract(MEM_ROOT *mem_root, String *str, if (!parsed) { String *s_p= item_jp->val_str(&tmp_path); - if (s_p && path_setup_nwc(&p, s_p->charset(), (const uchar *) s_p->ptr(), - (const uchar *) s_p->ptr() + s_p->length())) + + if (allow_wildcard) + { + if (s_p && + json_path_setup(&p, s_p->charset(), (const uchar *) s_p->ptr(), + (const uchar *) s_p->ptr() + s_p->length())) + error= true; + } + else + { + if (s_p && + path_setup_nwc(&p, s_p->charset(), (const uchar *) s_p->ptr(), + (const uchar *) s_p->ptr() + s_p->length())) + error= true; + } + + if (error) + { + report_path_error_ex(s_p->ptr(), &p, func_name, 1, + Sql_condition::WARN_LEVEL_WARN); return true; + } + parsed= constant; } @@ -853,7 +873,7 @@ continue_search: error_return: report_json_error_ex(js->ptr(), (json_engine_t*)&je, - (const char*)func_name_str->str , 0, + func_name, 0, Sql_condition::WARN_LEVEL_WARN); return true; } @@ -1139,8 +1159,18 @@ bool Item_json_str_multipath::fix_length_and_dec(THD *thd) bool Item_func_json_extract::fix_length_and_dec(THD *thd) { collation.set(args[0]->collation); - max_length= args[0]->max_length * (arg_count - 1); + /* *2 accounts for LOOSE json_nice() formatting (spaces after : and ,). */ + ulonglong char_length= + (ulonglong) args[0]->max_char_length() * (arg_count - 1) * 2; + + if (arg_count > 2) + { + /* Multiple paths: result is wrapped as [val1, val2, ...]. */ + char_length+= 2 + (arg_count - 2) * 2; + } + + fix_char_length_ulonglong(char_length); mark_constant_paths(paths, args+1, arg_count-1); set_maybe_null(); @@ -4131,6 +4161,7 @@ skip_search: goto null_return; str->length(0); + str->set_charset(collation.collation); if (str->append('[')) goto err_return; /* Out of memory. */ /* Parse the OBJECT collecting the keys. */ @@ -4854,6 +4885,7 @@ String *Item_func_json_normalize::val_str(String *buf) } buf->length(0); + buf->set_charset(collation.collation); if (buf->append(normalized_json.str, normalized_json.length)) { null_value= 1; @@ -5572,37 +5604,30 @@ error_return: String* Item_func_json_key_value::val_str(String *str) { - if ((null_value= args[0]->null_value) || - (null_value= args[1]->null_value)) - { - goto return_null; - } + if ((null_value= args[0]->null_value || args[1]->null_value)) + return NULL; + null_value= Json_path_extractor::extract(current_thd->mem_root, &tmp_str, args[0], args[1], collation.collation, &json_depth_array, - &func_name_str); + func_name_str.str, true); if (null_value) return NULL; json_scan_start(&je, tmp_str.charset(), (const uchar *) tmp_str.ptr(), (const uchar *) tmp_str.ptr() + tmp_str.length()); if (json_read_value(&je)) - { - report_json_error(str, &je, 0); - goto return_null; - } + goto return_error; str->length(0); if (get_key_value(&je, str)) - { - report_json_error(str, &je, 0); - goto return_null; - } + goto return_error; return str; -return_null: +return_error: + report_json_error(str, &je, 0); null_value= 1; return NULL; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index a5e678dda8e..5cf9ae92a0f 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -81,7 +81,7 @@ protected: bool extract(MEM_ROOT *mem_root, String *to, Item *js, Item *jp, CHARSET_INFO *cs, MEM_ROOT_DYNAMIC_ARRAY *, - LEX_CSTRING *func_name); + const char *func_name, bool allow_wildcard); void init_json_engine_stack(MEM_ROOT *mem_root); public: Json_path_extractor() {} diff --git a/sql/item_vectorfunc.h b/sql/item_vectorfunc.h index bcff3daa7df..8236b3c09af 100644 --- a/sql/item_vectorfunc.h +++ b/sql/item_vectorfunc.h @@ -21,6 +21,7 @@ #include "item.h" #include "lex_string.h" #include "item_func.h" +#include "sql_type_vector.h" class Item_func_vec_distance: public Item_real_func { @@ -97,6 +98,10 @@ public: bool fix_length_and_dec(THD *thd) override; Item_func_vec_fromtext(THD *thd, Item *a); String *val_str(String *buf) override; + const Type_handler *type_handler() const override + { return &type_handler_vector; } + Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override + { return create_table_field_from_handler(root, table); } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= { STRING_WITH_LEN("VEC_FromText") }; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index ae97285b179..aef9230dc4e 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -8353,17 +8353,17 @@ int Rows_log_event::find_row(rpl_group_info *rgi) found. I can see no scenario where it would be incorrect to chose the row to change only using a PK or an UNNI. */ - if (find_flag == HA_READ_KEY_EXACT && table->key_info->flags & HA_NOSAME) + if (find_flag == HA_READ_KEY_EXACT && m_key_info->flags & HA_NOSAME) { /* Unique does not have non nullable part */ - if (!(table->key_info->flags & HA_NULL_PART_KEY)) + if (!(m_key_info->flags & HA_NULL_PART_KEY)) { error= 0; goto end; } else { - KEY *keyinfo= table->key_info; + KEY *keyinfo= m_key_info; /* Unique has nullable part. We need to check if there is any field in the BI image that is null and part of UNNI. diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 556a80b1079..9998916fc81 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -1599,7 +1599,7 @@ void DsMrr_impl::reset_buffer_sizes(void *dsmrr_arg) void DsMrr_impl::redistribute_buffer_space(void *dsmrr_arg) { DsMrr_impl *dsmrr= (DsMrr_impl*)dsmrr_arg; - uchar *unused_start, *unused_end; + uchar *unused_start, *unused_end= nullptr; dsmrr->key_buffer->remove_unused_space(&unused_start, &unused_end); dsmrr->rowid_buffer.grow(unused_start, unused_end); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 98717995241..869adb1fc34 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -365,6 +365,7 @@ static const char *character_set_collations_str= Thread_cache thread_cache; static bool binlog_format_used= false; LEX_STRING opt_init_connect, opt_init_slave; +mysql_cond_t COND_slave_deadlock_handler; static DYNAMIC_ARRAY all_options; static longlong start_memory_used; @@ -759,7 +760,8 @@ mysql_mutex_t LOCK_crypt, LOCK_global_system_variables, LOCK_user_conn, - LOCK_error_messages; + LOCK_error_messages, + LOCK_slave_deadlock_handler; mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats, LOCK_global_table_stats, LOCK_global_index_stats; @@ -993,7 +995,8 @@ PSI_mutex_key key_LOCK_stats, PSI_mutex_key key_LOCK_gtid_waiting; PSI_mutex_key key_LOCK_after_binlog_sync; -PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered; +PSI_mutex_key key_LOCK_prepare_ordered, key_LOCK_commit_ordered, + key_LOCK_slave_deadlock_handler; PSI_mutex_key key_TABLE_SHARE_LOCK_share; PSI_mutex_key key_TABLE_SHARE_LOCK_statistics; PSI_mutex_key key_LOCK_ack_receiver; @@ -1075,6 +1078,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_prepare_ordered, "LOCK_prepare_ordered", PSI_FLAG_GLOBAL}, { &key_LOCK_after_binlog_sync, "LOCK_after_binlog_sync", PSI_FLAG_GLOBAL}, { &key_LOCK_commit_ordered, "LOCK_commit_ordered", PSI_FLAG_GLOBAL}, + { &key_LOCK_slave_deadlock_handler, "LOCK_slave_deadlock_handler", PSI_FLAG_GLOBAL}, { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0}, { &key_LOCK_slave_state, "LOCK_slave_state", 0}, { &key_LOCK_start_thread, "LOCK_start_thread", PSI_FLAG_GLOBAL}, @@ -1143,7 +1147,7 @@ PSI_cond_key key_TC_LOG_MMAP_COND_queue_busy; PSI_cond_key key_COND_rpl_thread_queue, key_COND_rpl_thread, key_COND_rpl_thread_stop, key_COND_rpl_thread_pool, key_COND_parallel_entry, key_COND_group_commit_orderer, - key_COND_prepare_ordered; + key_COND_prepare_ordered, key_COND_slave_deadlock_handler; PSI_cond_key key_COND_wait_gtid, key_COND_gtid_ignore_duplicates; PSI_cond_key key_COND_ack_receiver; @@ -1190,6 +1194,7 @@ static PSI_cond_info all_server_conds[]= { &key_COND_parallel_entry, "COND_parallel_entry", 0}, { &key_COND_group_commit_orderer, "COND_group_commit_orderer", 0}, { &key_COND_prepare_ordered, "COND_prepare_ordered", 0}, + { &key_COND_slave_deadlock_handler, "COND_slave_deadlock_handler", 0}, { &key_COND_start_thread, "COND_start_thread", PSI_FLAG_GLOBAL}, { &key_COND_wait_gtid, "COND_wait_gtid", 0}, { &key_COND_gtid_ignore_duplicates, "COND_gtid_ignore_duplicates", 0}, @@ -1201,7 +1206,7 @@ static PSI_cond_info all_server_conds[]= PSI_thread_key key_thread_delayed_insert, key_thread_handle_manager, key_thread_main, key_thread_one_connection, key_thread_signal_hand, - key_thread_slave_background, key_rpl_parallel_thread; + key_thread_slave_deadlock_handler, key_rpl_parallel_thread; PSI_thread_key key_thread_ack_receiver; static PSI_thread_info all_server_threads[]= @@ -1211,7 +1216,7 @@ static PSI_thread_info all_server_threads[]= { &key_thread_main, "main", PSI_FLAG_GLOBAL}, { &key_thread_one_connection, "one_connection", 0}, { &key_thread_signal_hand, "signal_handler", PSI_FLAG_GLOBAL}, - { &key_thread_slave_background, "slave_bg", PSI_FLAG_GLOBAL}, + { &key_thread_slave_deadlock_handler, "slave_deadlock_handler", PSI_FLAG_GLOBAL}, { &key_thread_ack_receiver, "Ack_receiver", PSI_FLAG_GLOBAL}, { &key_rpl_parallel_thread, "rpl_parallel", 0} }; @@ -2202,6 +2207,8 @@ static void clean_up_mutexes() mysql_cond_destroy(&COND_prepare_ordered); mysql_mutex_destroy(&LOCK_after_binlog_sync); mysql_mutex_destroy(&LOCK_commit_ordered); + mysql_mutex_destroy(&LOCK_slave_deadlock_handler); + mysql_cond_destroy(&COND_slave_deadlock_handler); #ifndef EMBEDDED_LIBRARY mysql_mutex_destroy(&LOCK_error_log); #endif @@ -4569,6 +4576,9 @@ static int init_thread_environment() MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_LOCK_commit_ordered, &LOCK_commit_ordered, MY_MUTEX_INIT_SLOW); + mysql_mutex_init(key_LOCK_slave_deadlock_handler, &LOCK_slave_deadlock_handler, + MY_MUTEX_INIT_SLOW); + mysql_cond_init(key_COND_slave_deadlock_handler, &COND_slave_deadlock_handler, NULL); mysql_mutex_init(key_LOCK_backup_log, &LOCK_backup_log, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_optimizer_costs, &LOCK_optimizer_costs, MY_MUTEX_INIT_FAST); @@ -6350,6 +6360,12 @@ int mysqld_main(int argc, char **argv) mysqld_port, MYSQL_COMPILATION_COMMENT); } +#ifdef HAVE_PAUSE_INSTRUCTION + if (global_system_variables.log_warnings > 2) + sql_print_information("Using PAUSE multiplier %u", + my_cpu_relax_multiplier); +#endif + #ifndef _WIN32 // try to keep fd=0 busy if (please_close_stdin && !freopen("/dev/null", "r", stdin)) @@ -6381,11 +6397,7 @@ int mysqld_main(int argc, char **argv) my_free(user); #ifdef WITH_WSREP - /* Stop wsrep threads in case they are running. */ - if (wsrep_running_threads > 0) - { - wsrep_shutdown_replication(); - } + wsrep_shutdown(); /* Release threads if they are waiting in WSREP_SYNC_WAIT_UPTO_GTID */ wsrep_gtid_server.signal_waiters(0, true); #endif diff --git a/sql/mysqld.h b/sql/mysqld.h index c5dd0e58a29..ef93892ec7a 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -394,7 +394,7 @@ extern PSI_cond_key key_TABLE_SHARE_COND_rotation; extern PSI_thread_key key_thread_delayed_insert, key_thread_handle_manager, key_thread_main, key_thread_one_connection, key_thread_signal_hand, - key_thread_slave_background, key_rpl_parallel_thread; + key_thread_slave_deadlock_handler, key_rpl_parallel_thread; extern PSI_file_key key_file_binlog, key_file_binlog_cache, key_file_binlog_index, key_file_binlog_index_cache, key_file_casetest, @@ -728,7 +728,8 @@ extern mysql_mutex_t LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_active_mi, LOCK_manager, LOCK_user_conn, - LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_backup_log, + LOCK_prepared_stmt_count, LOCK_error_messages, + LOCK_slave_deadlock_handler, LOCK_backup_log, LOCK_optimizer_costs; extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_global_system_variables; extern mysql_rwlock_t LOCK_all_status_vars; @@ -740,6 +741,7 @@ extern mysql_rwlock_t LOCK_ssl_refresh; extern mysql_prlock_t LOCK_system_variables_hash; extern mysql_cond_t COND_start_thread; extern mysql_cond_t COND_manager; +extern mysql_cond_t COND_slave_deadlock_handler; extern my_bool opt_use_ssl; extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index 452ec19b114..391d243b56c 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -5154,7 +5154,7 @@ int SJ_TMP_TABLE::sj_weedout_check_row(THD *thd) } // 3. Put the rowids - for (uint i=0; tab != tab_end; tab++, i++) + for (; tab != tab_end; tab++) { handler *h= tab->join_tab->table->file; if (tab->join_tab->table->maybe_null && tab->join_tab->table->null_row) diff --git a/sql/slave.cc b/sql/slave.cc index c6555369ec8..9d3feb1925b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -467,8 +467,114 @@ end: plugin_unlock(NULL, engine); } +static bool slave_deadlock_handler_thread_running; +static bool slave_deadlock_handler_thread_stop; static bool slave_background_thread_gtid_loaded; +struct slave_deadlock_kill_t { + slave_deadlock_kill_t *next; + THD *to_kill; +} *slave_deadlock_kill_list; + + +pthread_handler_t +slave_deadlock_handler(void *arg __attribute__((unused))) +{ + bool stop; + + my_thread_init(); + + mysql_mutex_lock(&LOCK_slave_deadlock_handler); + slave_deadlock_handler_thread_running= true; + mysql_cond_broadcast(&COND_slave_deadlock_handler); + do + { + slave_deadlock_kill_t *kill_list; + + for (;;) + { + stop= abort_loop || slave_deadlock_handler_thread_stop; + kill_list= slave_deadlock_kill_list; + if (stop || kill_list) + break; + mysql_cond_wait(&COND_slave_deadlock_handler, &LOCK_slave_deadlock_handler); + } + + slave_deadlock_kill_list= NULL; + mysql_mutex_unlock(&LOCK_slave_deadlock_handler); + + while (kill_list) + { + slave_deadlock_kill_t *p = kill_list; + THD *to_kill= p->to_kill; + kill_list= p->next; + + DBUG_EXECUTE_IF("rpl_delay_deadlock_kill", my_sleep(1500000);); + to_kill->awake(KILL_CONNECTION); + mysql_mutex_lock(&to_kill->LOCK_wakeup_ready); + to_kill->rgi_slave->killed_for_retry= + rpl_group_info::RETRY_KILL_KILLED; + mysql_cond_broadcast(&to_kill->COND_wakeup_ready); + mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready); + my_free(p); + } + mysql_mutex_lock(&LOCK_slave_deadlock_handler); + } while (!stop); + + slave_deadlock_handler_thread_running= false; + mysql_cond_broadcast(&COND_slave_deadlock_handler); + mysql_mutex_unlock(&LOCK_slave_deadlock_handler); + + my_thread_end(); + return 0; +} + + +/* + Start the slave deadlock handler thread. + + This thread is used to kill worker thread transactions during parallel + replication, when a storage engine attempts to take an errorneous + conflicting lock that would cause a deadlock. Killing is done + asynchroneously, as the kill may not be safe within the context of a + callback from inside storage engine locking code. +*/ +static int +start_slave_deadlock_handler_thread() +{ + pthread_t th; + + mysql_mutex_lock(&LOCK_slave_deadlock_handler); + slave_deadlock_handler_thread_running= false; + slave_deadlock_handler_thread_stop= false; + if (mysql_thread_create(key_thread_slave_deadlock_handler, + &th, &connection_attrib, slave_deadlock_handler, + NULL)) + { + sql_print_error("Failed to create thread while initialising slave"); + return 1; + } + + while (!slave_deadlock_handler_thread_running) + mysql_cond_wait(&COND_slave_deadlock_handler, &LOCK_slave_deadlock_handler); + mysql_mutex_unlock(&LOCK_slave_deadlock_handler); + + return 0; +} + + +static void +stop_slave_deadlock_handler_thread() +{ + mysql_mutex_lock(&LOCK_slave_deadlock_handler); + slave_deadlock_handler_thread_stop= true; + mysql_cond_broadcast(&COND_slave_deadlock_handler); + while (slave_deadlock_handler_thread_running) + mysql_cond_wait(&COND_slave_deadlock_handler, &LOCK_slave_deadlock_handler); + mysql_mutex_unlock(&LOCK_slave_deadlock_handler); +} + + static void bg_rpl_load_gtid_slave_state(void *) { THD *thd= new_bg_THD(); @@ -489,25 +595,27 @@ static void bg_rpl_load_gtid_slave_state(void *) delete thd; } -static void bg_slave_kill(void *victim) -{ - THD *to_kill= (THD *)victim; - DBUG_EXECUTE_IF("rpl_delay_deadlock_kill", my_sleep(1500000);); - to_kill->awake(KILL_CONNECTION); - mysql_mutex_lock(&to_kill->LOCK_wakeup_ready); - to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_KILLED; - mysql_cond_broadcast(&to_kill->COND_wakeup_ready); - mysql_mutex_unlock(&to_kill->LOCK_wakeup_ready); -} void slave_background_kill_request(THD *to_kill) { if (to_kill->rgi_slave->killed_for_retry) return; // Already deadlock killed. - to_kill->rgi_slave->killed_for_retry= rpl_group_info::RETRY_KILL_PENDING; - mysql_manager_submit(bg_slave_kill, to_kill); + slave_deadlock_kill_t *p= (slave_deadlock_kill_t *) + my_malloc(PSI_INSTRUMENT_ME, sizeof(*p), MYF(MY_WME)); + if (p) + { + p->to_kill= to_kill; + to_kill->rgi_slave->killed_for_retry= + rpl_group_info::RETRY_KILL_PENDING; + mysql_mutex_lock(&LOCK_slave_deadlock_handler); + p->next= slave_deadlock_kill_list; + slave_deadlock_kill_list= p; + mysql_cond_signal(&COND_slave_deadlock_handler); + mysql_mutex_unlock(&LOCK_slave_deadlock_handler); + } } + /* This function must only be called from a slave SQL thread (or worker thread), to ensure that the table_entry will not go away before we can lock the @@ -552,6 +660,9 @@ int init_slave() init_slave_psi_keys(); #endif + if (start_slave_deadlock_handler_thread()) + return 1; + if (global_rpl_thread_pool.init(opt_slave_parallel_threads)) return 1; @@ -783,6 +894,10 @@ bool init_slave_skip_errors(const char* arg) if (!system_charset_info->strnncoll((uchar*)arg,4,(const uchar*)"all",4)) { bitmap_set_all(&slave_error_mask); + bitmap_clear_bit(&slave_error_mask,ER_CONNECTION_KILLED); + sql_print_warning("Slave: ER_CONNECTION_KILLED (%d) is not allowed in " + "--slave-skip-errors=all. This error will never be skipped " + "by the slave.", ER_CONNECTION_KILLED); goto end; } for (p= arg ; *p; ) @@ -791,7 +906,18 @@ bool init_slave_skip_errors(const char* arg) if (!(p= str2int(p, 10, 0, LONG_MAX, &err_code))) break; if (err_code < MAX_SLAVE_ERROR) - bitmap_set_bit(&slave_error_mask,(uint)err_code); + { + if (err_code == ER_CONNECTION_KILLED) + { + sql_print_warning("Slave: ER_CONNECTION_KILLED (%d) is not allowed in " + "--slave-skip-errors. This error will never be skipped " + "by the slave.", ER_CONNECTION_KILLED); + } + else + { + bitmap_set_bit(&slave_error_mask,(uint)err_code); + } + } while (!my_isdigit(system_charset_info,*p) && *p) p++; } @@ -1273,6 +1399,7 @@ void slave_prepare_for_shutdown() mysql_mutex_lock(&LOCK_active_mi); master_info_index->free_connections(); mysql_mutex_unlock(&LOCK_active_mi); + stop_slave_deadlock_handler_thread(); // It's safe to destruct worker pool now when // all driver threads are gone. global_rpl_thread_pool.deactivate(); @@ -1306,6 +1433,8 @@ void end_slave() active_mi= 0; mysql_mutex_unlock(&LOCK_active_mi); + stop_slave_deadlock_handler_thread(); + global_rpl_thread_pool.destroy(); free_all_rpl_filters(); DBUG_VOID_RETURN; @@ -3364,9 +3493,8 @@ sql_delay_event(Log_event *ev, THD *thd, rpl_group_info *rgi) mysql_mutex_assert_owner(&rli->data_lock); DBUG_ASSERT(!rli->belongs_to_client()); - int type= ev->get_type_code(); - if (sql_delay && type != ROTATE_EVENT && - type != FORMAT_DESCRIPTION_EVENT && type != START_EVENT_V3) + Log_event_type type= ev->get_type_code(); + if (sql_delay && Log_event::is_group_event(type)) { // The time when we should execute the event. time_t sql_delay_end= @@ -5151,6 +5279,15 @@ pthread_handler_t handle_slave_sql(void *arg) DBUG_ASSERT(debug_sync_service); DBUG_ASSERT(!debug_sync_set_action(current_thd, STRING_WITH_LEN(act))); };); +#ifdef WITH_WSREP + DBUG_EXECUTE_IF("wsrep_async_slave_node_dropped_error", + if (WSREP(thd)) + { + wsrep_node_dropped= TRUE; + goto err_before_start; + } + ); +#endif /* WITH_WSREP */ #endif rli->parallel.reset(); @@ -5325,8 +5462,8 @@ pthread_handler_t handle_slave_sql(void *arg) mysql_mutex_unlock(&rli->data_lock); #ifdef WITH_WSREP wsrep_open(thd); - if (WSREP_ON_) - wsrep_wait_ready(thd); + if (WSREP_ON_ && !wsrep_wait_ready(thd)) + goto err; if (wsrep_before_command(thd)) { WSREP_WARN("Slave SQL wsrep_before_command() failed"); @@ -5549,21 +5686,25 @@ err_during_init: */ if (WSREP(thd) && wsrep_node_dropped && wsrep_restart_slave) { - if (wsrep_ready_get()) - { - WSREP_INFO("Slave error due to node temporarily non-primary" - "SQL slave will continue"); wsrep_node_dropped= FALSE; mysql_mutex_unlock(&rli->run_lock); - goto wsrep_restart_point; - } - else - { WSREP_INFO("Slave error due to node going non-primary"); WSREP_INFO("wsrep_restart_slave was set and therefore slave will be " "automatically restarted when node joins back to cluster"); - wsrep_restart_slave_activated= TRUE; - } + if (wsrep_wait_ready(thd)) + { + wsrep_close(thd); + delete serial_rgi; + if (thd_initialized) + server_threads.erase(thd); + delete thd; + goto wsrep_restart_point; + } + else + { + /* The node is being shutdown. Fallthrough. */ + mysql_mutex_lock(&rli->run_lock); + } } wsrep_close(thd); #endif /* WITH_WSREP */ @@ -6675,7 +6816,7 @@ dbug_gtid_accept: crc= my_checksum(crc, (const uchar *) buf, event_len - BINLOG_CHECKSUM_LEN); - int4store(&buf[event_len - BINLOG_CHECKSUM_LEN], crc); + int4store(const_cast(& buf[event_len - BINLOG_CHECKSUM_LEN]), crc); } } if (likely(!rli->relay_log.write_event_buffer((uchar*)buf, event_len))) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 132c08cebbc..2bdc21e8087 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3960,6 +3960,9 @@ exit: privilege_t acl_get_all3(Security_context *sctx, const char *db, bool db_is_patern) { + if (!initialized) + return DB_ACLS; + privilege_t access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, db_is_patern); if (sctx->priv_role[0]) diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index b902c4ae440..1c009cb9981 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1003,7 +1003,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* Fields we want to have statistics for */ bitmap_clear_all(&tab->has_value_set); - for (uint fields= 0; *field_ptr; field_ptr++, fields++) + for (; *field_ptr; field_ptr++) { Field *field= *field_ptr; if (field->flags & LONG_UNIQUE_HASH_FIELD) diff --git a/sql/sql_const.h b/sql/sql_const.h index 2c72ef457ce..e51d4d18807 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -175,6 +175,12 @@ #ifndef __has_feature #define __has_feature(x) 0 #endif +/* + Note, rather than trying to micro adjust these every time + slightly different test fails, potentially on slightly different + compiler, look at adjusting the test. For example main.sp-error + at Bug#15192. +*/ #if defined(__clang__) && __has_feature(memory_sanitizer) && !defined(DBUG_OFF) #define STACK_MIN_SIZE 44000 #else diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index db25478aa31..c4f60a133ef 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -933,6 +933,7 @@ exit: if (derived->table && derived->table->s->tmp_table) free_tmp_table(thd, derived->table); delete derived->derived_result; + derived->derived_result= NULL; } } else diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ea23c19d0bf..d974dd54a2b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -990,7 +990,8 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, #endif /* EMBEDDED_LIBRARY */ { if (prepare_for_replace(table, info.handle_duplicates, info.ignore)) - DBUG_RETURN(1); + goto abort; + /** This is a simple check for the case when the table has a trigger that reads from it, or when the statement invokes a stored function @@ -4620,7 +4621,7 @@ bool select_insert::prepare_eof(bool in_create_table) /* Don't convert the warning to error in case statistics updation fails */ Abort_on_warning_instant_set save_abort_on_warning(thd, false); - error= table->file->extra(HA_EXTRA_END_ALTER_COPY); + error= table->file->extra(HA_EXTRA_END_COPY); if (error == HA_ERR_FOUND_DUPP_KEY) { uint key_nr= table->file->get_dup_key(error); @@ -4778,7 +4779,7 @@ void select_insert::abort_result_set() finalize_replace(table, info.handle_duplicates, info.ignore); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - if (table->file->extra(HA_EXTRA_ABORT_ALTER_COPY) == HA_ERR_ROLLBACK) + if (table->file->extra(HA_EXTRA_ABORT_COPY) == HA_ERR_ROLLBACK) thd->transaction_rollback_request= true; /* If at least one row has been inserted/modified and will stay in @@ -5261,8 +5262,13 @@ select_create::prepare(List &_values, SELECT_LEX_UNIT *u) !table->s->long_unique_table && !table->s->hlindexes()) { table->file->ha_start_bulk_insert((ha_rows) 0); - if (thd->lex->duplicates == DUP_ERROR && !thd->lex->ignore) - table->file->extra(HA_EXTRA_BEGIN_ALTER_COPY); + if (thd->lex->duplicates == DUP_ERROR) + { + static_assert(int{HA_EXTRA_BEGIN_ALTER_IGNORE_COPY} == + int{HA_EXTRA_BEGIN_COPY} + 1, ""); + table->file->extra(ha_extra_function(int{HA_EXTRA_BEGIN_COPY} + + thd->lex->ignore)); + } table->file->extra(HA_EXTRA_WRITE_CACHE); } thd->abort_on_warning= !info.ignore && thd->is_strict_mode(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 8148444c732..5f8818e82cd 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3021,7 +3021,7 @@ void st_select_lex_node::init_query_common() into the front of the stranded_clean_list: before: root -> B -> A after: root -> this -> B -> A - During cleanup, the stranded units are cleaned in FIFO order. + During cleanup, the stranded units are cleaned in LIFO order (parent-first). */ void st_select_lex_unit::remember_my_cleanup() { @@ -6582,6 +6582,7 @@ SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel) SELECT_LEX *dummy_select; SELECT_LEX_UNIT *unit; Table_ident *ti; + Item *sel_item; DBUG_ENTER("LEX::wrap_select_chain_into_derived"); if (!(dummy_select= alloc_select(TRUE))) @@ -6599,6 +6600,19 @@ SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel) DBUG_RETURN(NULL); /* add SELECT list*/ + if (sel->item_list.elements) + { + List_iterator li(sel->item_list); + while ((sel_item= li++)) + { + Item *item= new (thd->mem_root) Item_field(thd, context, sel_item->name); + if (item == NULL || + add_item_to_list(thd, item)) + goto err; + } + dummy_select->with_wild= sel->with_wild; + } + else { Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str); if (item == NULL) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 669daba74b0..591ee70e547 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1601,8 +1601,10 @@ public: 1 request of thread shutdown, i. e. if command is COM_QUIT/COM_SHUTDOWN */ -dispatch_command_return dispatch_command(enum enum_server_command command, THD *thd, - char* packet, uint packet_length, bool blocking) +dispatch_command_return dispatch_command(enum enum_server_command command, + THD *thd, + char* packet, uint packet_length, + bool blocking) { NET *net= &thd->net; bool error= 0; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 7bce1949149..d676a022c12 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4262,7 +4262,6 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { partition_info *part_info= table->part_info; uint num_parts= part_info->get_tot_partitions(); - uint i, part_id; uint sub_part= num_parts; uint32 part_part= num_parts; KEY *key_info= NULL; @@ -4410,9 +4409,11 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, part_spec->start_part= sub_part; part_spec->end_part=sub_part+ (part_info->num_subparts*(part_info->num_parts-1)); - for (i= 0, part_id= sub_part; i < part_info->num_parts; +#if 0 // FIXME: empty loop! + for (uint i= 0; part_id= sub_part; i < part_info->num_parts; i++, part_id+= part_info->num_subparts) ; //Set bit part_id in bit array +#endif } } if (found_part_field) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4836f596a97..2d04676cad7 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3857,7 +3857,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, char *comment= static_cast(alloc_root(mem_root, max_comment_len + 1)); char *optname; - int index= 0, UNINIT_VAR(offset); + int UNINIT_VAR(offset); st_mysql_sys_var *opt, **plugin_option; st_bookmark *v; @@ -3910,7 +3910,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, */ for (plugin_option= tmp->plugin->system_vars; - plugin_option && *plugin_option; plugin_option++, index++) + plugin_option && *plugin_option; plugin_option++) { opt= *plugin_option; @@ -3967,7 +3967,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, } for (plugin_option= tmp->plugin->system_vars; - plugin_option && *plugin_option; plugin_option++, index++) + plugin_option && *plugin_option; plugin_option++) { switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) { case PLUGIN_VAR_BOOL: diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 863f03698a4..78dfec2b2a3 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -471,7 +471,6 @@ int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond { DBUG_ENTER("PROFILING::fill_statistics_info"); TABLE *table= tables->table; - ulonglong row_number= 0; QUERY_PROFILE *query; /* Go through each query in this thread's stored history... */ @@ -495,7 +494,7 @@ int PROFILING::fill_statistics_info(THD *thd_arg, TABLE_LIST *tables, Item *cond for (entry_iterator= query->entries.new_iterator(); entry_iterator != NULL; entry_iterator= query->entries.iterator_next(entry_iterator), - previous=entry, row_number++) + previous=entry) { entry= query->entries.iterator_value(entry_iterator); seq= entry->m_seq; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a46aabfa485..9d87dd99a52 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -503,7 +503,7 @@ inline void fix_checksum(enum_binlog_checksum_alg checksum_alg, String *packet, ha_checksum crc; crc= my_checksum(0, (uchar *)packet->ptr() + ev_offset, data_len - BINLOG_CHECKSUM_LEN); - int4store(packet->ptr() + ev_offset + data_len - BINLOG_CHECKSUM_LEN, crc); + int4store(const_cast(packet->ptr() + ev_offset + data_len - BINLOG_CHECKSUM_LEN), crc); } @@ -4647,12 +4647,15 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) lex_mi->log_file_name || lex_mi->pos || lex_mi->relay_log_name || lex_mi->relay_log_pos) { + if (mi->using_gtid != Master_info::USE_GTID_NO) + { push_warning_printf( thd, Sql_condition::WARN_LEVEL_NOTE, WARN_OPTION_CHANGING, ER_THD(thd, WARN_OPTION_CHANGING), "CHANGE MASTER TO", "Using_Gtid", mi->using_gtid_astext(mi->using_gtid), mi->using_gtid_astext(Master_info::USE_GTID_NO)); - mi->using_gtid= Master_info::USE_GTID_NO; + mi->using_gtid= Master_info::USE_GTID_NO; + } } /* diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index c51cfb648cc..1876539625f 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -324,7 +324,7 @@ public: ((uint8 *) values)[i]= (uint8) (val * prec_factor()); return; case DOUBLE_PREC_HB: - int2store(values + i * 2, val * prec_factor()); + int2store(values + i * 2, (uint16)(val * prec_factor())); return; default: DBUG_ASSERT(0); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8b19e6947ee..c0795cb2ab5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -9594,6 +9594,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, { Alter_drop *drop; drop_it.rewind(); + List dropped_fk; while ((drop=drop_it++)) { switch (drop->type) { case Alter_drop::KEY: @@ -9622,7 +9623,14 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, while (FOREIGN_KEY_INFO *f_key= fk_key_it++) { if (Lex_ident_column(*f_key->foreign_id).streq(drop->name)) + { + List_iterator check_it(dropped_fk); + while (LEX_CSTRING *dropped_name = check_it++) + if (Lex_ident_column(*f_key->foreign_id).streq(*dropped_name)) + goto fk_not_found; + dropped_fk.push_back(f_key->foreign_id); goto fk_found; + } } goto fk_not_found; fk_found: @@ -9914,6 +9922,7 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, when a foreign key has the same table as child and parent. */ List_iterator fk_parent_key_it(fk_parent_key_list); + List keys_to_remove; while ((f_key= fk_parent_key_it++)) { @@ -9933,10 +9942,31 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, drop->name.streq(*f_key->foreign_id) && table->s->db.streq(*f_key->foreign_db) && table->s->table_name.streq(*f_key->foreign_table)) - fk_parent_key_it.remove(); + { + keys_to_remove.push_back(f_key); + break; + } } } + IF_DBUG(uint removed= 0,); + /* Remove the identified keys */ + List_iterator remove_it(keys_to_remove); + while ((f_key = remove_it++)) + { + fk_parent_key_it.rewind(); + while (FOREIGN_KEY_INFO *fk= fk_parent_key_it++) + { + if (fk == f_key) + { + fk_parent_key_it.remove(); + IF_DBUG(removed++,); + break; + } + } + } + DBUG_ASSERT(keys_to_remove.elements == removed); + IF_DBUG(removed= 0,); /* If there are FKs in which this table is parent which were not dropped we need to prevent ALTER deleting rows from the table, @@ -10007,6 +10037,7 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, by this ALTER TABLE. */ List_iterator fk_key_it(fk_child_key_list); + keys_to_remove.empty(); while ((f_key= fk_key_it++)) { @@ -10018,10 +10049,31 @@ static bool fk_prepare_copy_alter_table(THD *thd, TABLE *table, /* Names of foreign keys in InnoDB are case-insensitive. */ if ((drop->type == Alter_drop::FOREIGN_KEY) && (Lex_ident_column(*f_key->foreign_id).streq(drop->name))) - fk_key_it.remove(); + { + keys_to_remove.push_back(f_key); + break; + } } } + /* Remove the identified keys */ + List_iterator remove_it2(keys_to_remove); + while ((f_key = remove_it2++)) + { + fk_key_it.rewind(); + while (FOREIGN_KEY_INFO *fk= fk_key_it++) + { + if (fk == f_key) + { + fk_key_it.remove(); + IF_DBUG(removed++,); + break; + } + } + } + + DBUG_ASSERT(keys_to_remove.elements == removed); + fk_key_it.rewind(); while ((f_key= fk_key_it++)) { @@ -12811,9 +12863,10 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, thd->progress.max_counter= from->file->records(); time_to_report_progress= MY_HOW_OFTEN_TO_WRITE/10; - /* for now, InnoDB needs the undo log for ALTER IGNORE */ - if (!ignore && !to->s->hlindexes()) - to->file->extra(HA_EXTRA_BEGIN_ALTER_COPY); + static_assert(int{HA_EXTRA_BEGIN_ALTER_IGNORE_COPY} == + int{HA_EXTRA_BEGIN_COPY} + 1, ""); + if (!to->s->hlindexes()) + to->file->extra(ha_extra_function(int{HA_EXTRA_BEGIN_COPY} + ignore)); if (!(error= info.read_record())) { @@ -13000,13 +13053,14 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, } bulk_insert_started= 0; - if (!ignore && !to->s->hlindexes() && error <= 0) + if (error <= 0 && !to->s->hlindexes()) { - int alt_error= to->file->extra(HA_EXTRA_END_ALTER_COPY); + Abort_on_warning_instant_set save_abort_on_warning(thd, false); + int alt_error= to->file->extra(HA_EXTRA_END_COPY); if (alt_error > 0) { error= alt_error; - to->file->extra(HA_EXTRA_ABORT_ALTER_COPY); + to->file->extra(HA_EXTRA_ABORT_COPY); copy_data_error_ignore(error, false, to, thd, alter_ctx); } } @@ -13142,6 +13196,9 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, if (error > 0 && !from->s->tmp_table) { + /* Abort the operation which invoked extra(HA_EXTRA_BEGIN_COPY) + or extra(HA_EXTRA_BEGIN_ALTER_IGNORE_COPY) */ + to->file->extra(HA_EXTRA_ABORT_COPY); /* We are going to drop the temporary table */ to->file->extra(HA_EXTRA_PREPARE_FOR_DROP); } diff --git a/sql/sql_union.cc b/sql/sql_union.cc index e485bb9d6e4..2dc2ed4d93c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2733,8 +2733,6 @@ err: bool st_select_lex_unit::cleanup() { - cleanup_stranded_units(); - bool error= 0; DBUG_ENTER("st_select_lex_unit::cleanup"); @@ -2823,6 +2821,11 @@ bool st_select_lex_unit::cleanup() delete pushdown_unit; pushdown_unit= nullptr; + /* + Cleanup stranded units only after this unit has completed its own + cleanup, ensuring a parent-first (LIFO) cleanup order for merged tables. + */ + cleanup_stranded_units(); DBUG_RETURN(error); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 450a1b3a975..7a32a1b1e5b 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1761,7 +1761,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *view_table_alias, if (view_query_lex->first_select_lex()->options & OPTION_TO_QUERY_CACHE) parent_query_lex->first_select_lex()->options|= OPTION_TO_QUERY_CACHE; - parent_query_lex->default_used= view_query_lex->default_used; + parent_query_lex->default_used|= view_query_lex->default_used; #ifndef NO_EMBEDDED_ACCESS_CHECKS if (view_table_alias->view_suid) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4348d77e5ae..c9826639eaa 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2421,14 +2421,14 @@ master_def: { mi->master_ssl_crlpath= path; }; } - | MASTER_HEARTBEAT_PERIOD_SYM '=' num_or_default + | MASTER_HEARTBEAT_PERIOD_SYM '=' opt_plus num_or_default { - if ($3) + if ($4) { uint32_t milliseconds; bool overprecise; auto decimal_buf= my_decimal(), - *decimal= $3->val_decimal(&decimal_buf); + *decimal= $4->val_decimal(&decimal_buf); DBUG_ASSERT(decimal); if (Master_info_file::Heartbeat_period_value::from_decimal( milliseconds, *decimal, overprecise diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 1abf5cbd241..6c8cd3eef12 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6736,9 +6736,10 @@ static Sys_var_ulong Sys_wsrep_mysql_replication_bundle( static Sys_var_mybool Sys_wsrep_slave_FK_checks( "wsrep_slave_FK_checks", "Should slave thread do " - "foreign key constraint checks", + "foreign key constraint checks (deprecated, has no effect)", GLOBAL_VAR(wsrep_slave_FK_checks), - CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + CMD_LINE(OPT_ARG), DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, + ON_CHECK(0), ON_UPDATE(0), DEPRECATED(1010, "")); // since 10.6.26 static Sys_var_mybool Sys_wsrep_slave_UK_checks( "wsrep_slave_UK_checks", "Should slave thread do " diff --git a/sql/table.cc b/sql/table.cc index e81ca13a4db..3ac7f206645 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6701,6 +6701,8 @@ int TABLE::verify_constraints(bool ignore_failure) field_error.append('.'); } field_error.append((*chk)->name); + if (ignore_failure) + in_use->clear_error(); my_error(ER_CONSTRAINT_FAILED, MYF(ignore_failure ? ME_WARNING : 0), field_error.c_ptr(), s->db.str, s->table_name.str); @@ -8295,8 +8297,7 @@ void TABLE::mark_columns_per_binlog_row_image() be added to read_set either. */ -bool TABLE::mark_virtual_columns_for_write(bool insert_fl - __attribute__((unused))) +bool TABLE::mark_virtual_columns_for_write(bool insert_fl) { Field **vfield_ptr, *tmp_vfield; bool bitmap_updated= false; @@ -8311,9 +8312,30 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl (tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG | PART_INDIRECT_KEY_FLAG))) { - bitmap_set_bit(write_set, tmp_vfield->field_index); - mark_virtual_column_with_deps(tmp_vfield); - bitmap_updated= true; + if (insert_fl) + { + bitmap_set_bit(write_set, tmp_vfield->field_index); + mark_virtual_column_with_deps(tmp_vfield); + bitmap_updated= true; + } + else + { + MY_BITMAP *save_read_set= read_set; + Item *vcol_item= tmp_vfield->vcol_info->expr; + DBUG_ASSERT(vcol_item); + bitmap_clear_all(&tmp_set); + read_set= &tmp_set; + vcol_item->walk(&Item::register_field_in_read_map, nullptr, + WALK_SUBQUERY); + read_set= save_read_set; + if (bitmap_is_overlapping(&tmp_set, write_set)) + { + bitmap_set_bit(write_set, tmp_vfield->field_index); + bitmap_set_bit(read_set, tmp_vfield->field_index); + bitmap_union(read_set, &tmp_set); + bitmap_updated= true; + } + } } } if (bitmap_updated) @@ -8933,6 +8955,7 @@ void TABLE_LIST::reinit_before_use(THD *thd) parent_embedding->nested_join->join_list.head() == embedded); mdl_request.ticket= NULL; + derived_result= NULL; } @@ -9363,7 +9386,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) /* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */ update= (!vcol_info->is_stored() && (vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) && - !bitmap_is_set(read_set, vf->field_index)); + bitmap_is_set(read_set, vf->field_index)); swap_values= 1; break; } diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc index e9a3d965774..d59fa0eee54 100644 --- a/sql/threadpool_generic.cc +++ b/sql/threadpool_generic.cc @@ -1140,7 +1140,7 @@ static void queue_put(thread_group_t *thread_group, TP_connection_generic *conne static bool too_many_threads(thread_group_t *thread_group) { - return (thread_group->active_thread_count >= 1+(int)threadpool_oversubscribe + return (thread_group->active_thread_count > 1+(int)threadpool_oversubscribe && !thread_group->stalled); } diff --git a/sql/unireg.cc b/sql/unireg.cc index 0821e728d0d..1cd4bf6408e 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -778,7 +778,7 @@ static bool pack_expression(String *buf, Virtual_column_info *vcol, my_error(ER_EXPRESSION_IS_TOO_BIG, MYF(0), vcol_type_name(type)); return 1; } - int2store(buf->ptr() + len_off, expr_len); + int2store(const_cast(buf->ptr() + len_off), expr_len); return 0; } diff --git a/sql/wsrep_high_priority_service.cc b/sql/wsrep_high_priority_service.cc index 146c9ca2131..0d90edba6e2 100644 --- a/sql/wsrep_high_priority_service.cc +++ b/sql/wsrep_high_priority_service.cc @@ -115,9 +115,8 @@ static void wsrep_setup_uk_and_fk_checks(THD* thd) else thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS; - if (wsrep_slave_FK_checks == FALSE || - (wsrep_check_mode(WSREP_MODE_APPLIER_SKIP_FK_CHECKS_IN_IST) && - !wsrep_ready_get())) + if (wsrep_check_mode(WSREP_MODE_APPLIER_SKIP_FK_CHECKS_IN_IST) && + !wsrep_ready_get()) thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS; else thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 998eb4f7260..8dcf6229916 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2008, 2025, Codership Oy - Copyright (c) 2020, 2026, MariaDB + Copyright (c) 2020, 2025, MariaDB + Copyright (c) 2026, MariaDB plc 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 @@ -116,8 +117,6 @@ uint wsrep_gtid_domain_id=0; // Domain id on above structure /* Other configuration variables and their default values. */ my_bool wsrep_incremental_data_collection= 0; // Incremental data collection -my_bool wsrep_restart_slave_activated= 0; // Node has dropped, and slave - // restart will be needed bool wsrep_new_cluster= false; // Bootstrap the cluster? int wsrep_slave_count_change= 0; // No. of appliers to stop/start int wsrep_to_isolation= 0; // No. of active TO isolation threads @@ -271,11 +270,17 @@ static char provider_name[256]= { 0, }; static char provider_version[256]= { 0, }; static char provider_vendor[256]= { 0, }; +enum WsrepState { + NOT_READY, + READY, + IN_SHUTDOWN, +}; +static std::atomic wsrep_state(NOT_READY); + /* * Wsrep status variables. LOCK_status must be locked When modifying * these variables, */ -std::atomic wsrep_ready(false); my_bool wsrep_connected = FALSE; const char* wsrep_cluster_state_uuid= cluster_uuid_str; long long wsrep_cluster_conf_id = WSREP_SEQNO_UNDEFINED; @@ -582,7 +587,7 @@ void wsrep_verify_SE_checkpoint(const wsrep_uuid_t& uuid, */ my_bool wsrep_ready_get (void) { - return wsrep_ready; + return wsrep_state == READY; } int wsrep_show_ready(THD *thd, SHOW_VAR *var, void *buff, @@ -1168,12 +1173,23 @@ void wsrep_stop_replication(THD *thd) wsrep_stop_replication_common(thd); } -void wsrep_shutdown_replication() +void wsrep_shutdown() { - WSREP_INFO("Shutdown replication"); - wsrep_stop_replication_common(nullptr); - /* Undocking the thread specific data. */ - set_current_thd(nullptr); + /* Signal ready state waiters that we're shutting down. */ + mysql_mutex_lock(&LOCK_wsrep_ready); + DBUG_ASSERT(wsrep_state != IN_SHUTDOWN); + wsrep_state = IN_SHUTDOWN; + mysql_cond_signal(&COND_wsrep_ready); + mysql_mutex_unlock(&LOCK_wsrep_ready); + + /* Stop wsrep threads in case they are running. */ + if (wsrep_running_threads > 0) + { + WSREP_INFO("Shutdown replication"); + wsrep_stop_replication_common(nullptr); + /* Undocking the thread specific data. */ + set_current_thd(nullptr); + } } bool wsrep_start_replication(const char *wsrep_cluster_address) @@ -2866,11 +2882,11 @@ static int wsrep_TOI_begin(THD *thd, const char *db, const char *table, WSREP_DEBUG("TOI Begin: %s", wsrep_thd_query(thd)); DEBUG_SYNC(thd, "wsrep_toi_begin"); - if (!wsrep_ready || + if (!wsrep_ready_get() || wsrep_can_run_in_toi(thd, db, table, table_list, create_info) == false) { WSREP_DEBUG("No TOI for %s", wsrep_thd_query(thd)); - if (!wsrep_ready) + if (!wsrep_ready_get()) { my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0)); push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, @@ -3263,14 +3279,276 @@ void wsrep_to_isolation_end(THD *thd) req->thread_id, wsrep_thd_trx_seqno(req), \ wsrep_thd_client_mode_str(req), wsrep_thd_client_state_str(req), \ wsrep_thd_transaction_state_str(req), wsrep_thd_is_BF(req, false), \ - req->get_command(), req->lex->sql_command, req->query(), \ + req->get_command(), req->lex->sql_command, wsrep_thd_query(req), \ gra->thread_id, wsrep_thd_trx_seqno(gra), \ wsrep_thd_client_mode_str(gra), wsrep_thd_client_state_str(gra), \ wsrep_thd_transaction_state_str(gra), wsrep_thd_is_BF(gra, false), \ - gra->get_command(), gra->lex->sql_command, gra->query()); + gra->get_command(), gra->lex->sql_command, wsrep_thd_query(gra)); + +/** Helper function to output wsrep state to a string. + +@param thd thread handle +@param granted true if this thread same as thread holding MDL-lock +@param str string containing wsrep state +*/ +static void wsrep_get_state(const THD* thd, const bool granted, String *str) +{ + str->append(STRING_WITH_LEN(granted ? "granted " : "request ")); + str->append_ulonglong((unsigned long long)thd->thread_id); + str->append(STRING_WITH_LEN(":")); + + if (WSREP(thd)) + str->append(STRING_WITH_LEN("WSREP ")); + if (wsrep_thd_is_BF(thd, false)) + str->append(STRING_WITH_LEN("BF ")); + else + str->append(STRING_WITH_LEN("LOCAL ")); + if (thd->wsrep_aborter || wsrep_thd_is_aborting(thd)) + str->append(STRING_WITH_LEN("ABORTING ")); + if (wsrep_thd_is_SR(thd)) + str->append(STRING_WITH_LEN("SR ")); + if (thd->wsrep_trx().active()) + str->append(STRING_WITH_LEN("WSREP TRX ")); + if (wsrep_thd_is_toi(thd)) + str->append(STRING_WITH_LEN("TOI ")); + if (wsrep_thd_is_applying(thd)) + str->append(STRING_WITH_LEN("APPLYING ")); + if (thd->current_backup_stage != BACKUP_FINISHED) + str->append(STRING_WITH_LEN("BACKUP ")); + if (thd->global_read_lock.is_acquired()) + { + if (thd->lex->type & (REFRESH_READ_LOCK|REFRESH_FOR_EXPORT)) + str->append(STRING_WITH_LEN("FTFE ")); + else + str->append(STRING_WITH_LEN("FTWRL ")); + } + if (thd->locked_tables_mode == LTM_LOCK_TABLES || + thd->variables.option_bits & OPTION_TABLE_LOCK) + str->append(STRING_WITH_LEN("LOCK TABLES ")); + + str->append(STRING_WITH_LEN(": ")); + const char* query= wsrep_thd_query(thd); + str->append(query, strlen(query)); +} + +/* MDL-log mode */ +typedef enum +{ + WSREP_MDL_DEBUG=0, + WSREP_MDL_INFO, + WSREP_MDL_ERROR +} wsrep_mdl_log_t; + +/** Helper function to log MDL-conflict. + +@param level log level either DEBUG, INFO or ERROR +@param msg log message +@param request_thd requestor thread +@param granted_thd thread holding MDL-lock +@param ticket conflicting MDL-ticket +@param key MDL-key +*/ +static void wsrep_mdl_log(wsrep_mdl_log_t level, + const char* msg, + const THD* request_thd, + const THD* granted_thd, + const MDL_ticket *ticket, + const MDL_key *key) +{ + const char* schema= key->db_name(); + const int schema_len= key->db_name_length(); + const char* name= key->name(); + const int name_len= key->name_length(); + + switch(level) + { + case WSREP_MDL_DEBUG: + WSREP_MDL_LOG(DEBUG, msg, + schema, schema_len, name, name_len, + request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + break; + case WSREP_MDL_INFO: + WSREP_MDL_LOG(INFO, msg, + schema, schema_len, name, name_len, + request_thd, granted_thd); + ticket->wsrep_report(wsrep_debug); + break; + case WSREP_MDL_ERROR: + WSREP_MDL_LOG(ERROR, msg, + schema, schema_len, name, name_len, + request_thd, granted_thd); + ticket->wsrep_report(true); + break; + default: + DBUG_ASSERT(0); // bug + break; + } +} + +/** Helper function to dump wsrep state to error log. + +@param msg Message for error log +@param thd Thread handle +@param granted true if this thread is holding MDL-lock +*/ +static void wsrep_log_state(const char *msg, const THD *thd, bool granted) +{ + char buff[2048]; + String buffer(buff, sizeof(buff), system_charset_info); + wsrep_get_state(thd, granted, &buffer); + WSREP_DEBUG(msg, buffer.c_ptr()); +} + +/** This function handles MDL-conflict when thread holding MDL-lock + (granted_thd) is TOI or applying i.e BF. + + If granted_thd is aborting + wait for MDL-locks to be released + else if granted_thd is SR and requestor is DDL + abort granted_thd + else + not possible BF-BF case + +@param request_thd requestor thread +@param granted_thd thread holding conflicting MDL-lock +@param ticket conflicting MDL-ticket +@param key MDL key +*/ +static void wsrep_handle_granted_bf( + THD* request_thd, + THD* granted_thd, + const MDL_ticket *ticket, + const MDL_key *key) +{ + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_kill); + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_data); + + if (wsrep_debug) + { + wsrep_log_state("wsrep_handle_granted_bf() : (%s)", request_thd, false); + wsrep_log_state("wsrep_handle_granted_bf() : (%s)", granted_thd, true); + } + + if (wsrep_thd_is_aborting(granted_thd)) + { + // Granted thread is aborting, we wait it to release MDL-locs + } + else if (wsrep_thd_is_SR(granted_thd) && wsrep_thd_is_toi(request_thd)) + { + // Granted thread is executing streaming replication and request is DDL, + // abort granted + wsrep_mdl_log(WSREP_MDL_INFO, "MDL conflict, DDL vs SR", + request_thd, granted_thd, ticket, key); + wsrep_abort_thd(request_thd, granted_thd, 1); + } + else + { + // This case BF-BF is not possible so fail on debug + wsrep_mdl_log(WSREP_MDL_ERROR, "MDL BF-BF conflict", + request_thd, granted_thd, ticket, key); + DBUG_ASSERT(!(wsrep_thd_is_BF(granted_thd, false) && + wsrep_thd_is_BF(request_thd, false))); + } +} + +/** This function handles MDL-conflict when thread holding MDL-lock + (granted_thd) has ongoing + BACKUP + OR FLUSH TABLES WITH READ LOCK + OR FLUSH TABLES FOR EXPORT + OR LOCK TABLES + + Requestor may kill only ongoing BACKUP if user has so configured, + all other cases it must wait MDL-lock to be released. + +@param request_thd requestor thread +@param granted_thd thread holding conflicting MDL-lock +@param ticket conflicting MDL-ticket +@param key MDL key +*/ +static void wsrep_handle_locked(THD* request_thd, + THD* granted_thd, + const MDL_ticket *ticket, + const MDL_key *key) +{ + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_kill); + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_data); + DBUG_ASSERT(!wsrep_thd_is_BF(granted_thd, false)); + + if (wsrep_debug) + { + wsrep_log_state("wsrep_handle_locked() : (%s)", request_thd, false); + wsrep_log_state("wsrep_handle_locked() : (%s)", granted_thd, true); + } + + if (granted_thd->current_backup_stage != BACKUP_FINISHED && + wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP)) + { + // User has allowed killing mariabackup + wsrep_mdl_log(WSREP_MDL_INFO, "MDL conflict, ongoing backup", + request_thd, granted_thd, ticket, key); + wsrep_abort_thd(request_thd, granted_thd, true); + } + // else requestor must wait for MDL-lock to be released +} + +/** This function handles MDL-conflict when thread holding MDL-lock + (granted_thd) is not BF (brute force) and requestor is + BF. + +If thread has active wsrep transaction it can be wsrep aborted +else + send KILL_QUERY_HARD and handler abort transaction + +@param request_thd requestor thread +@param granted_thd thread holding conflicting MDL-lock +@param ticket conflicting MDL-ticket +@param key MDL key +*/ +static void wsrep_abort_granted(THD* request_thd, + THD* granted_thd, + const MDL_ticket *ticket, + const MDL_key *key) +{ + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_kill); + mysql_mutex_assert_owner(&granted_thd->LOCK_thd_data); + DBUG_ASSERT(!wsrep_thd_is_BF(granted_thd, false)); + DBUG_ASSERT(wsrep_thd_is_BF(request_thd, false)); + + if (wsrep_debug) + { + wsrep_log_state("wsrep_abort_granted() : (%s)", request_thd, false); + wsrep_log_state("wsrep_abort_granted() : (%s)", granted_thd, true); + } + + wsrep_mdl_log(WSREP_MDL_DEBUG, "MDL conflict-> BF abort", + request_thd, granted_thd, ticket, key); + + if (granted_thd->wsrep_trx().active()) + { + // Granted thread has active wsrep transaction, abort it + wsrep_abort_thd(request_thd, granted_thd, 1); + } + else + { + // Granted thread is not wsrep transaction or it has no + // active transaction e.g. CREATE TABLE X AS SELECT, + // signal KILL_QUERY and abort transaction + granted_thd->awake_no_mutex(KILL_QUERY_HARD); + ha_abort_transaction(request_thd, granted_thd, TRUE); + } +} /** - Check if request for the metadata lock should be granted to the requester. + This function handles MDL-conflict between thread requesting MDL-lock + and thread that already has acquired MDL-lock i.e. granted thread. + Either requesting thread will wait for MDL-lock to be released or + granted thread will be BF-killed, aborted or signaled with + KILL_QUERY_HARD. + + * If requester is not wsrep thread it must wait for MDL to be released. + * If requester is not TOI or applying it must wait for MDL to be released. @param requestor_ctx The MDL context of the requestor @param ticket MDL ticket for the requested lock @@ -3283,145 +3561,74 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx, { THD *request_thd= requestor_ctx->get_thd(); + /* Note here request_thd == current_thd */ /* Fallback to the non-wsrep behaviour */ if (!WSREP(request_thd)) return; - mysql_mutex_lock(&request_thd->LOCK_thd_data); + /* Fallback to non-wsrep behaviour if request is not TOI or + applying. + */ + if (!wsrep_thd_is_BF(request_thd, FALSE)) return; // requestor needs to wait - // If requestor is not BF it has to wait for - // release of MDL-lock. - if (wsrep_thd_is_toi(request_thd) || - wsrep_thd_is_applying(request_thd)) + THD *granted_thd= ticket->get_ctx()->get_thd(); + + THD_STAGE_INFO(request_thd, stage_waiting_isolation); + + // Thread should not hold any mutexes below debug sync point + DEBUG_SYNC(request_thd, "before_wsrep_thd_abort"); + DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", { + const char act[]= "now " + "SIGNAL sync.before_wsrep_thd_abort_reached " + "WAIT_FOR signal.before_wsrep_thd_abort"; + DBUG_ASSERT(!debug_sync_set_action(request_thd, STRING_WITH_LEN(act))); + };); + + /* We should hold + THD::LOCK_thd_data to protect granted from concurrent usage + and THD::LOCK_thd_kill to protect it from disconnect or delete. + */ + mysql_mutex_lock(&granted_thd->LOCK_thd_kill); + mysql_mutex_lock(&granted_thd->LOCK_thd_data); + + if (wsrep_debug) { - THD *granted_thd= ticket->get_ctx()->get_thd(); + wsrep_log_state("wsrep_handle_mdl_conflict() : (%s)", request_thd, false); + wsrep_log_state("wsrep_handle_mdl_conflict() : (%s)", granted_thd, true); + } - const char* schema= key->db_name(); - int schema_len= key->db_name_length(); - const char* name= key->name(); - int name_len= key->name_length(); - - THD_STAGE_INFO(request_thd, stage_waiting_isolation); - mysql_mutex_unlock(&request_thd->LOCK_thd_data); - WSREP_MDL_LOG(DEBUG, "MDL conflict ", schema, schema_len, - name, name_len, request_thd, granted_thd); - ticket->wsrep_report(wsrep_debug); - - DEBUG_SYNC(request_thd, "before_wsrep_thd_abort"); - DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", { - const char act[]= "now " - "SIGNAL sync.before_wsrep_thd_abort_reached " - "WAIT_FOR signal.before_wsrep_thd_abort"; - DBUG_ASSERT(!debug_sync_set_action(request_thd, STRING_WITH_LEN(act))); - };); - - /* Here we will call wsrep_abort_transaction so we should hold - THD::LOCK_thd_data to protect victim from concurrent usage - and THD::LOCK_thd_kill to protect from disconnect or delete. - */ - mysql_mutex_lock(&granted_thd->LOCK_thd_kill); - mysql_mutex_lock(&granted_thd->LOCK_thd_data); - - if (granted_thd->wsrep_aborter != 0) - { - // Granted thread has being already selected as a victim for - // BF kill, we can wait until it releases MDL-lock - DBUG_ASSERT(granted_thd->wsrep_aborter == request_thd->thread_id); - WSREP_DEBUG("BF thread waiting for a victim to release locks"); - } - else if (wsrep_thd_is_toi(granted_thd) || - wsrep_thd_is_applying(granted_thd)) - { - // Here both request thread and granted thread are either TOI - // or applying. - if (wsrep_thd_is_aborting(granted_thd)) - { - // Granted thread is aborting, we wait it to release MDL-locs - WSREP_DEBUG("BF thread for %s waiting for thread in aborting state for %s", - wsrep_thd_query(request_thd), - wsrep_thd_query(granted_thd)); - ticket->wsrep_report(wsrep_debug); - } - else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd)) - { - // Granted thread is executing streaming replication and request is DDL, - // abort granted - WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR", - schema, schema_len, name, name_len, - request_thd, granted_thd); - wsrep_abort_thd(request_thd, granted_thd, 1); - } - else - { - DBUG_ASSERT(0); - // In this case request thread waits - WSREP_MDL_LOG(INFO, "MDL BF-BF conflict", schema, schema_len, - name, name_len, request_thd, granted_thd); - ticket->wsrep_report(true); - } - } - /* If granted thread has - ongoing BACKUP OR - ongoing FLUSH TABLES WITH READ LOCK OR - ongoing FLUSH TABLES FOR EXPORT OR LOCK TABLES - */ - else if (granted_thd->current_backup_stage != BACKUP_FINISHED || - granted_thd->global_read_lock.is_acquired() || - granted_thd->locked_tables_mode == LTM_LOCK_TABLES) - { - WSREP_DEBUG("BF thread waiting for %s", - (granted_thd->current_backup_stage != BACKUP_FINISHED ? "BACKUP" : - (granted_thd->global_read_lock.is_acquired() ? "FTWRL" : "LOCK TABLES"))); - ticket->wsrep_report(wsrep_debug); - - if (granted_thd->current_backup_stage != BACKUP_FINISHED && - wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP)) - { - // User has allowed killing mariabackup - wsrep_abort_thd(request_thd, granted_thd, 1); - } - } - else - { - WSREP_MDL_LOG(DEBUG, "MDL conflict-> BF abort", schema, schema_len, - name, name_len, request_thd, granted_thd); - WSREP_DEBUG("wsrep_handle_mdl_conflict -> BF abort for %s", - wsrep_thd_query(granted_thd)); - ticket->wsrep_report(wsrep_debug); - - if (granted_thd->wsrep_trx().active()) - { - // Granted thread has active wsrep transaction - wsrep_abort_thd(request_thd, granted_thd, 1); - } - else if (!WSREP(granted_thd) || - wsrep_thd_is_BF(granted_thd, false)) - { - // Granted thread is not wsrep transaction or it is not BF kill it - WSREP_MDL_LOG(DEBUG, "MDL conflict-> kill", schema, schema_len, - name, name_len, request_thd, granted_thd); - granted_thd->awake_no_mutex(KILL_QUERY_HARD); - ha_abort_transaction(request_thd, granted_thd, TRUE); - } - else - { - WSREP_DEBUG("MDL conflig-> wait request BF:%ld:%s granted %s:%ld query %s", - request_thd->thread_id, - wsrep_thd_query(request_thd), - (wsrep_thd_is_BF(granted_thd, FALSE) ? "LOCAL" : "BF"), - granted_thd->thread_id, - wsrep_thd_query(granted_thd)); - } - } - - mysql_mutex_unlock(&granted_thd->LOCK_thd_data); - mysql_mutex_unlock(&granted_thd->LOCK_thd_kill); - DEBUG_SYNC(request_thd, "after_wsrep_thd_abort"); + if (granted_thd->wsrep_aborter != 0) + { + // Granted thread has being already selected as a victim for + // BF kill, we can wait until it releases MDL-lock + DBUG_ASSERT(granted_thd->wsrep_aborter == request_thd->thread_id); + } + else if (granted_thd->current_backup_stage != BACKUP_FINISHED || + granted_thd->global_read_lock.is_acquired() || + granted_thd->locked_tables_mode == LTM_LOCK_TABLES || + granted_thd->variables.option_bits & OPTION_TABLE_LOCK) + { + /* Granted thread has + ongoing BACKUP OR + ongoing FLUSH TABLES WITH READ LOCK OR + ongoing FLUSH TABLES FOR EXPORT OR + ongoing LOCK TABLES + */ + wsrep_handle_locked(request_thd, granted_thd, ticket, key); + } + else if (wsrep_thd_is_BF(granted_thd, FALSE)) + { + // Granted thread is either TOI or applying + wsrep_handle_granted_bf(request_thd, granted_thd, ticket, key); } else { - // Request thread is normal local transaction it has to wait - mysql_mutex_unlock(&request_thd->LOCK_thd_data); + // Granted thread is not brute-force thread, we can abort it + wsrep_abort_granted(request_thd, granted_thd, ticket, key); } + + mysql_mutex_unlock(&granted_thd->LOCK_thd_data); + mysql_mutex_unlock(&granted_thd->LOCK_thd_kill); + DEBUG_SYNC(request_thd, "after_wsrep_thd_abort"); } /**/ @@ -3772,25 +3979,25 @@ wsrep_error_label: int wsrep_create_trigger_query(THD *thd, uchar** buf, size_t* buf_len) { - LEX *lex= thd->lex; String stmt_query; LEX_CSTRING definer_user; LEX_CSTRING definer_host; - if (!lex->definer) + LEX_USER *definer= thd->lex->definer; + if (!definer) { if (!thd->slave_thread) { - if (!(lex->definer= create_default_definer(thd, false))) + if (!(definer= create_default_definer(thd, false))) return 1; } } - if (lex->definer) + if (definer) { /* SUID trigger. */ - LEX_USER *d= get_current_user(thd, lex->definer); + LEX_USER *d= get_current_user(thd, definer); if (!d) return 1; @@ -4039,31 +4246,45 @@ bool wsrep_consistency_check(THD *thd) return thd->wsrep_consistency_check == CONSISTENCY_CHECK_RUNNING; } -// Wait until wsrep has reached ready state -void wsrep_wait_ready(THD *thd) +bool wsrep_wait_ready(THD *thd) { // First check not locking the mutex. - if (wsrep_ready) - return; + switch (wsrep_state.load()) { + case NOT_READY: + break; + case READY: + return true; + case IN_SHUTDOWN: + return false; + } mysql_mutex_lock(&LOCK_wsrep_ready); - while(!wsrep_ready) + while(!wsrep_state) { WSREP_INFO("Waiting to reach ready state"); mysql_cond_wait(&COND_wsrep_ready, &LOCK_wsrep_ready); } - WSREP_INFO("ready state reached"); mysql_mutex_unlock(&LOCK_wsrep_ready); + WSREP_INFO("ready state reached"); + /* It may happen we stop waiting and immediately transition + to not ready state when we reach this line. It's a spurious + wakeup we cannot deal with, but the best we can do is to return + readiness indication. That's why we should compare to + IN_SHUTDOWN rather than returning wsrep_ready_get(). */ + return wsrep_state != IN_SHUTDOWN; } void wsrep_ready_set(bool ready_value) { WSREP_DEBUG("Setting wsrep_ready to %d", ready_value); mysql_mutex_lock(&LOCK_wsrep_ready); - wsrep_ready= ready_value; - // Signal if we have reached ready state - if (ready_value) - mysql_cond_signal(&COND_wsrep_ready); + /* Only transition if we're not shutting down. */ + if (wsrep_state != IN_SHUTDOWN) { + wsrep_state= ready_value ? READY : NOT_READY; + // Signal if we have reached ready state + if (ready_value) + mysql_cond_signal(&COND_wsrep_ready); + } mysql_mutex_unlock(&LOCK_wsrep_ready); } diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index f00e63ac409..2e5d2b1fc68 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -78,7 +78,6 @@ extern my_bool wsrep_log_conflicts; extern ulong wsrep_mysql_replication_bundle; extern my_bool wsrep_load_data_splitting; extern my_bool wsrep_restart_slave; -extern my_bool wsrep_restart_slave_activated; extern my_bool wsrep_slave_FK_checks; extern my_bool wsrep_slave_UK_checks; extern ulong wsrep_trx_fragment_unit; @@ -211,7 +210,7 @@ extern void wsrep_close_applier_threads(int count); /* new defines */ extern void wsrep_stop_replication(THD *thd); extern bool wsrep_start_replication(const char *wsrep_cluster_address); -extern void wsrep_shutdown_replication(); +extern void wsrep_shutdown(); extern bool wsrep_check_mode (enum_wsrep_mode mask); extern bool wsrep_check_mode_after_open_table (THD *thd, const handlerton *hton, TABLE_LIST *tables); @@ -280,7 +279,6 @@ static inline bool wsrep_cluster_address_exists() } extern my_bool wsrep_ready_get(); -extern void wsrep_ready_wait(); extern mysql_mutex_t LOCK_wsrep_ready; extern mysql_cond_t COND_wsrep_ready; @@ -593,7 +591,17 @@ enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit); wsrep::key wsrep_prepare_key_for_toi(const char* db, const char* table, enum wsrep::key::type type); -void wsrep_wait_ready(THD *thd); +/** + * Wait until wsrep has reached ready state + * @return true if the node is ready, false if it's in shutdown + * + * @note The function may spuriously stop waiting and return + * readiness indication while in reality the node is not being + * ready. It's the best effort, and it's false-positive. + * In contrast, returning false is guaranteed to only happen + * when the node is indeed in shutdown. + */ +bool wsrep_wait_ready(THD *thd); void wsrep_ready_set(bool ready_value); /** diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 6e20f803cbb..c4c7046f111 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -1158,24 +1158,14 @@ IO_AND_CPU_COST ha_archive::rnd_pos_time(ha_rows rows) */ int ha_archive::index_read(uchar *buf, const uchar *key, uint key_len, enum ha_rkey_function find_flag) -{ - int rc; - DBUG_ENTER("ha_archive::index_read"); - rc= index_read_idx(buf, active_index, key, key_len, find_flag); - DBUG_RETURN(rc); -} - - -int ha_archive::index_read_idx(uchar *buf, uint index, const uchar *key, - uint key_len, enum ha_rkey_function find_flag) { int rc; bool found= 0; - KEY *mkey= &table->key_info[index]; + KEY *mkey= &table->key_info[active_index]; current_k_offset= mkey->key_part->offset; current_key= key; current_key_len= key_len; - DBUG_ENTER("ha_archive::index_read_idx"); + DBUG_ENTER("ha_archive::index_read"); rc= rnd_init(TRUE); diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index 497f7c06217..1ea1ce5573f 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -111,11 +111,9 @@ public: ulonglong blocks) override; IO_AND_CPU_COST rnd_pos_time(ha_rows rows) override; int index_init(uint keynr, bool sorted) override; - virtual int index_read(uchar * buf, const uchar * key, - uint key_len, enum ha_rkey_function find_flag) - override; - virtual int index_read_idx(uchar * buf, uint index, const uchar * key, - uint key_len, enum ha_rkey_function find_flag); + int index_read(uchar * buf, const uchar * key, + uint key_len, enum ha_rkey_function find_flag) + override; int index_next(uchar * buf) override; int open(const char *name, int mode, uint test_if_locked) override; int close(void) override; diff --git a/storage/columnstore/columnstore b/storage/columnstore/columnstore index df0dc363078..ab1c56f1ad0 160000 --- a/storage/columnstore/columnstore +++ b/storage/columnstore/columnstore @@ -1 +1 @@ -Subproject commit df0dc363078a2016b256cef2ba8145ce267dc2d1 +Subproject commit ab1c56f1ad0d1fd0863269f2a8d90b06c1d11716 diff --git a/storage/connect/filamtxt.cpp b/storage/connect/filamtxt.cpp index 5e4526e437b..fa48cbfa7ae 100644 --- a/storage/connect/filamtxt.cpp +++ b/storage/connect/filamtxt.cpp @@ -1859,13 +1859,13 @@ int BINFAM::ReadBuffer(PGLOBAL g) // Read the prefix giving the row length if (!fread(&Recsize, sizeof(size_t), 1, Stream)) { if (!feof(Stream)) { - snprintf(g->Message, sizeof(g->Message), "Error reading line prefix\n"); + snprintf(g->Message, sizeof(g->Message), "Error reading line prefix"); return RC_FX; } else return RC_EF; } else if (Recsize > (unsigned)Buflen) { - snprintf(g->Message, sizeof(g->Message), "Record too big (Recsize=%zd Buflen=%d)\n", Recsize, Buflen); + snprintf(g->Message, sizeof(g->Message), "Record too big (Recsize=%zd Buflen=%d)", Recsize, Buflen); return RC_FX; } // endif Recsize diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index 446306535cd..0b7ac0e715a 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -6365,7 +6365,10 @@ static int connect_assisted_discovery(handlerton *, THD* thd, err: if (rc) - my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + if (g->Message[0]) + my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); + else + my_error(ER_GET_ERRNO, MYF(0), rc, "CONNECT"); PopUser(xp); return rc; diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index 95b3024d60a..10ce3fde921 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -1770,7 +1770,7 @@ void JVALUE::SetValue(PGLOBAL g, PVAL valp) DataType = TYPE_BINT; break; default: - snprintf(g->Message, sizeof(g->Message), "Unsupported typ %d\n", valp->GetType()); + snprintf(g->Message, sizeof(g->Message), "Unsupported typ %d", valp->GetType()); throw(777); } // endswitch Type diff --git a/storage/connect/macutil.cpp b/storage/connect/macutil.cpp index 99b2cce8ade..fda47b53880 100644 --- a/storage/connect/macutil.cpp +++ b/storage/connect/macutil.cpp @@ -145,7 +145,7 @@ bool MACINFO::GetFixedInfo(PGLOBAL g) } // endif drc if (drc != ERROR_SUCCESS) { - snprintf(g->Message, sizeof(g->Message), "GetNetworkParams failed. Rc=%08x\n", drc); + snprintf(g->Message, sizeof(g->Message), "GetNetworkParams failed. Rc=%08x", drc); return true; } // endif drc diff --git a/storage/connect/myconn.cpp b/storage/connect/myconn.cpp index addcb0f6865..87d91716e40 100644 --- a/storage/connect/myconn.cpp +++ b/storage/connect/myconn.cpp @@ -760,7 +760,7 @@ int MYSQLC::ExecSQL(PGLOBAL g, const char *query, int *w) } else { // m_Rows = (int)mysql_affected_rows(m_DB); m_Rows = (int)m_DB->affected_rows; - snprintf(g->Message, sizeof(g->Message), "Affected rows: %d\n", m_Rows); + snprintf(g->Message, sizeof(g->Message), "Affected rows: %d", m_Rows); rc = RC_NF; } // endif field count diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index 27bdfee5f35..e9c8ba0a804 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -1804,7 +1804,7 @@ void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL jvp) break; default: - snprintf(g->Message, sizeof(g->Message), "Unsupported column type %d\n", vp->GetType()); + snprintf(g->Message, sizeof(g->Message), "Unsupported column type %d", vp->GetType()); throw 888; } // endswitch Type diff --git a/storage/connect/tabmac.cpp b/storage/connect/tabmac.cpp index 723dc359ee8..a07f9de8507 100644 --- a/storage/connect/tabmac.cpp +++ b/storage/connect/tabmac.cpp @@ -159,7 +159,7 @@ bool TDBMAC::GetFixedInfo(PGLOBAL g) } // endif drc if (drc != ERROR_SUCCESS) { - snprintf(g->Message, sizeof(g->Message), "GetNetworkParams failed. Rc=%08x\n", drc); + snprintf(g->Message, sizeof(g->Message), "GetNetworkParams failed. Rc=%08x", drc); return true; } // endif drc diff --git a/storage/connect/tabutil.cpp b/storage/connect/tabutil.cpp index ffd07b548a6..f9dbda576d0 100644 --- a/storage/connect/tabutil.cpp +++ b/storage/connect/tabutil.cpp @@ -91,7 +91,7 @@ TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, key[++k] = 0; if (!(s = alloc_table_share(db, name, key, ++k))) { - strcpy(g->Message, "Error allocating share\n"); + strcpy(g->Message, "Error allocating share"); return NULL; } // endif s @@ -109,7 +109,7 @@ TABLE_SHARE *GetTableShare(PGLOBAL g, THD *thd, const char *db, if (thd->is_error()) thd->clear_error(); // Avoid stopping info commands - snprintf(g->Message, sizeof(g->Message), "Error %d opening share\n", s->error); + snprintf(g->Message, sizeof(g->Message), "Error %d opening share", s->error); free_table_share(s); return NULL; } // endif open_table_def diff --git a/storage/connect/tabwmi.cpp b/storage/connect/tabwmi.cpp index 69ef529bf5c..6ccbef8af05 100644 --- a/storage/connect/tabwmi.cpp +++ b/storage/connect/tabwmi.cpp @@ -120,7 +120,7 @@ PWMIUT InitWMI(PGLOBAL g, PCSZ nsp, PCSZ classname) res = wp->Svc->GetObject(bstr_t(p), 0, 0, &wp->Cobj, 0); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed GetObject %s in %s\n", classname, nsp); + snprintf(g->Message, sizeof(g->Message), "failed GetObject %s in %s", classname, nsp); wp->Svc->Release(); wp->Svc = NULL; // MUST be set to NULL (why?) return NULL; @@ -165,12 +165,12 @@ PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info) res = wp->Cobj->Get(bstr_t("__Property_Count"), 0, &val, NULL, NULL); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed Get(__Property_Count) res=%d\n", res); + snprintf(g->Message, sizeof(g->Message), "failed Get(__Property_Count) res=%d", res); goto err; } // endif res if (!(n = val.lVal)) { - snprintf(g->Message, sizeof(g->Message), "Class %s in %s has no properties\n", + snprintf(g->Message, sizeof(g->Message), "Class %s in %s has no properties", cls, nsp); goto err; } // endif res @@ -183,7 +183,7 @@ PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info) NULL, &prnlist); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed GetNames res=%d\n", res); + snprintf(g->Message, sizeof(g->Message), "failed GetNames res=%d", res); goto err; } // endif res @@ -195,7 +195,7 @@ PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info) res = SafeArrayGetElement(prnlist, &i, &propname); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed GetArrayElement res=%d\n", res); + snprintf(g->Message, sizeof(g->Message), "failed GetArrayElement res=%d", res); goto err; } // endif res @@ -222,7 +222,7 @@ PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info) res = wp->Cobj->BeginEnumeration(WBEM_FLAG_NONSYSTEM_ONLY); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed BeginEnumeration hr=%d\n", res); + snprintf(g->Message, sizeof(g->Message), "failed BeginEnumeration hr=%d", res); qrp = NULL; goto err; } // endif hr @@ -231,7 +231,7 @@ PQRYRES WMIColumns(PGLOBAL g, PCSZ nsp, PCSZ cls, bool info) res = wp->Cobj->Next(0, &propname, &val, &type, NULL); if (FAILED(res)) { - snprintf(g->Message, sizeof(g->Message), "failed getting Next hr=%d\n", res); + snprintf(g->Message, sizeof(g->Message), "failed getting Next hr=%d", res); qrp = NULL; goto err; } else if (res == WBEM_S_NO_MORE_DATA) { diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index b79f57f71f6..d199397c3b4 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -1302,7 +1302,10 @@ bool ha_federated::create_where_from_key(String *to, bool both_not_null= (start_key != NULL && end_key != NULL) ? TRUE : FALSE; const uchar *ptr; - uint remainder, length; +#ifndef DBUG_OFF + uint remainder; +#endif + uint length; char tmpbuff[FEDERATED_QUERY_BUFFER_SIZE]; String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info); const key_range *ranges[2]= { start_key, end_key }; @@ -1329,10 +1332,14 @@ bool ha_federated::create_where_from_key(String *to, } for (key_part= key_info->key_part, +#ifndef DBUG_OFF remainder= key_info->user_defined_key_parts, +#endif length= ranges[i]->length, ptr= ranges[i]->key; ; +#ifndef DBUG_OFF remainder--, +#endif key_part++) { Field *field= key_part->field; diff --git a/storage/federatedx/ha_federatedx.cc b/storage/federatedx/ha_federatedx.cc index 9e46abcf70b..ff0ca86abb7 100644 --- a/storage/federatedx/ha_federatedx.cc +++ b/storage/federatedx/ha_federatedx.cc @@ -1243,7 +1243,10 @@ bool ha_federatedx::create_where_from_key(String *to, bool both_not_null= (start_key != NULL && end_key != NULL) ? TRUE : FALSE; const uchar *ptr; - uint remainder, length; +#ifndef DBUG_OFF + uint remainder; +#endif + uint length; char tmpbuff[FEDERATEDX_QUERY_BUFFER_SIZE]; String tmp(tmpbuff, sizeof(tmpbuff), system_charset_info); const key_range *ranges[2]= { start_key, end_key }; @@ -1271,10 +1274,14 @@ bool ha_federatedx::create_where_from_key(String *to, } for (key_part= key_info->key_part, +#ifndef DBUG_OFF remainder= key_info->user_defined_key_parts, +#endif length= ranges[i]->length, ptr= ranges[i]->key; ; +#ifndef DBUG_OFF remainder--, +#endif key_part++) { Field *field= key_part->field; diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index b57f5ec5d2e..e0dbe083fdc 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -2167,7 +2167,7 @@ btr_cur_ins_lock_and_undo( || dict_index_is_clust(index) || (flags & BTR_CREATE_FLAG)); ut_ad((flags & BTR_NO_UNDO_LOG_FLAG) - || !index->table->skip_alter_undo); + || index->table->skip_alter_undo != dict_table_t::NO_UNDO); ut_ad(mtr->is_named_space(index->table->space)); diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 9b9f84f773c..98e3c5dd3df 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -651,7 +651,6 @@ buf_block_t *buf_buddy_shrink(buf_page_t *bpage, buf_block_t *block) noexcept ulint size= page_zip_get_size(&bpage->zip); ulint i= buf_buddy_get_slot(size); - ut_ad(buf_pool.will_be_withdrawn(bpage->zip.data, size)); ut_ad(bpage->can_relocate()); ut_ad(i <= BUF_BUDDY_SIZES); ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN)); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 1e2f02b2f0c..ed078d91bed 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1391,7 +1391,6 @@ bool buf_pool_t::create() noexcept } MEM_UNDEFINED(memory_unaligned, size); - ut_dontdump(memory_unaligned, size, true); memory= memory_unaligned + alignment_waste; size_unaligned= size; size-= alignment_waste; @@ -1406,7 +1405,7 @@ bool buf_pool_t::create() noexcept #ifdef UNIV_PFS_MEMORY PSI_MEMORY_CALL(memory_alloc)(mem_key_buf_buf_pool, actual_size, &owner); #endif -#ifdef _WIN32 +#ifndef _AIX if (!my_virtual_mem_commit(memory, actual_size)) { my_virtual_mem_release(memory_unaligned, size_unaligned); @@ -1414,6 +1413,7 @@ bool buf_pool_t::create() noexcept memory_unaligned= nullptr; goto oom; } + ut_dontdump(memory_unaligned, size_unaligned, true); #else update_malloc_size(actual_size, 0); #endif @@ -1893,12 +1893,6 @@ inline void buf_pool_t::shrunk(size_t size, size_t reduced) noexcept ut_ad(size + reduced == size_in_bytes); size_in_bytes_requested= size; size_in_bytes= size; -# ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT - /* Only page_guess() may read this memory, which after - my_virtual_mem_decommit() may be zeroed out or preserve its original - contents. Try to catch any unintended reads outside page_guess(). */ - MEM_UNDEFINED(memory + size, size_in_bytes_max - size); -# else for (size_t n= page_hash.pad(page_hash.n_cells), i= 0; i < n; i+= page_hash.ELEMENTS_PER_LATCH + 1) { @@ -1909,7 +1903,6 @@ inline void buf_pool_t::shrunk(size_t size, size_t reduced) noexcept guess before we invoke my_virtual_mem_decommit() below. */ latch.unlock(); } -# endif my_virtual_mem_decommit(memory + size, reduced); #ifdef UNIV_PFS_MEMORY PSI_MEMORY_CALL(memory_free)(mem_key_buf_buf_pool, reduced, owner); @@ -1978,6 +1971,7 @@ ATTRIBUTE_COLD void buf_pool_t::resize(size_t size, THD *thd) noexcept return; } + ut_dontdump(memory + old_size, size - old_size, true); size_in_bytes_requested= size; size_in_bytes= size; @@ -2648,38 +2642,18 @@ uint32_t buf_pool_t::page_guess(buf_block_t *b, page_hash_latch &latch, /* On at least two Intel Xeon of different generation, it turns out that transactional_shared_lock_guard would perform worse here. */ latch.lock_shared(); -#ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT - /* shrunk() and my_virtual_mem_decommit() could retain the original - contents of the virtual memory range or zero it out immediately or - with a delay. Any zeroing out may lead to a false positive for - b->page.id() == id but never for b->page.state(). At the time of - the shrunk() call, shrink() and buf_LRU_block_free_non_file_page() - should guarantee that b->page.state() is equal to - buf_page_t::NOT_USED (0) for all to-be-freed blocks. */ -#else /* shrunk() made the memory inaccessible. */ if (UNIV_UNLIKELY(reinterpret_cast(b) >= memory + size_in_bytes)) { latch.unlock_shared(); return 0; } -#endif /* This synchronizes with buf_page_t::init() */ uint32_t state{b->page.zip.fix.load(std::memory_order_acquire)}; const page_id_t block_id{b->page.id()}; -#ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT - /* shrunk() may have invoked MEM_UNDEFINED() on this memory to be able - to catch any unintended access elsewhere in our code. */ - MEM_MAKE_DEFINED(&block_id, sizeof block_id); -#endif if (id == block_id) { -#ifndef HAVE_UNACCESSIBLE_AFTER_MEM_DECOMMIT - /* shrunk() may have invoked MEM_UNDEFINED() on this memory to be able - to catch any unintended access elsewhere in our code. */ - MEM_MAKE_DEFINED(&state, sizeof state); -#endif /* Ignore guesses that point to read-fixed blocks. We can only avoid a race condition by looking up the block via page_hash. */ if ((state >= buf_page_t::FREED && state < buf_page_t::READ_FIX) || @@ -3752,15 +3726,15 @@ ATTRIBUTE_COLD void buf_pool_t::clear_hash_index() noexcept @retval nullptr if all freed */ void buf_pool_t::assert_all_freed() noexcept { - mysql_mutex_lock(&mutex); + mysql_mutex_assert_owner(&mutex); - for (char *extent= memory, - *end= memory + block_descriptors_in_bytes(n_blocks); - extent < end; extent+= innodb_buffer_pool_extent_size) - for (buf_block_t *block= reinterpret_cast(extent), - *extent_end= block + - pages_in_extent[srv_page_size_shift - UNIV_PAGE_SIZE_SHIFT_MIN]; - block < extent_end && reinterpret_cast(block) < end; block++) + for (char *extent= memory, + *end= memory + block_descriptors_in_bytes(n_blocks); + extent < end; extent+= innodb_buffer_pool_extent_size) + for (buf_block_t *block= reinterpret_cast(extent), + *extent_end= block + + pages_in_extent[srv_page_size_shift - UNIV_PAGE_SIZE_SHIFT_MIN]; + block < extent_end && reinterpret_cast(block) < end; block++) { if (!block->page.in_file()) continue; @@ -3790,8 +3764,6 @@ void buf_pool_t::assert_all_freed() noexcept fixed_or_dirty: ib::fatal() << "Page " << block->page.id() << " still fixed or dirty"; } - - mysql_mutex_unlock(&mutex); } #endif /* UNIV_DEBUG */ @@ -3802,33 +3774,6 @@ void buf_refresh_io_stats() noexcept buf_pool.old_stat = buf_pool.stat; } -/** Invalidate all pages in the buffer pool. -All pages must be in a replaceable state (not modified or latched). */ -void buf_pool_invalidate() noexcept -{ - /* It is possible that a write batch that has been posted - earlier is still not complete. For buffer pool invalidation to - proceed we must ensure there is NO write activity happening. */ - - os_aio_wait_until_no_pending_writes(false); - ut_d(buf_pool.assert_all_freed()); - mysql_mutex_lock(&buf_pool.mutex); - - while (UT_LIST_GET_LEN(buf_pool.LRU)) { - buf_LRU_scan_and_free_block(); - } - - ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); - - buf_pool.freed_page_clock = 0; - buf_pool.LRU_old = NULL; - buf_pool.LRU_old_len = 0; - buf_pool.stat.init(); - - buf_refresh_io_stats(); - mysql_mutex_unlock(&buf_pool.mutex); -} - #ifdef UNIV_DEBUG /** Validate the buffer pool. */ void buf_pool_t::validate() noexcept diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 1dc9e0c57fa..ab9dbe2897e 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -174,9 +174,15 @@ fail: ut_ad(init_mtr.get_savepoint() == 1); ut_ad(init_mtr.m_memo[0].object == new_block); ut_ad(init_mtr.m_memo[0].type == MTR_MEMO_PAGE_X_MODIFY); + new_block->page.fix(); init_mtr.m_memo[0].type= MTR_MEMO_PAGE_X_FIX; init_mtr.rollback_to_savepoint(0, 1); init_mtr.m_log.erase(); + mysql_mutex_lock(&buf_pool.mutex); + new_block->page.unfix(); + ut_d(bool freed=) buf_LRU_free_page(&new_block->page, true); + ut_ad(freed); + mysql_mutex_unlock(&buf_pool.mutex); if (i == size / 2) ut_a(id.page_no() == size); @@ -203,11 +209,6 @@ fail: TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N); mtr.commit(); - buf_flush_wait_flushed(mtr.commit_lsn()); - - /* Remove doublewrite pages from LRU */ - buf_pool_invalidate(); - sql_print_information("InnoDB: Doublewrite buffer created"); goto start_again; } @@ -316,7 +317,7 @@ func_exit: else { alignas(8) char checkpoint[8]; - mach_write_to_8(checkpoint, log_sys.next_checkpoint_lsn); + mach_write_to_8(checkpoint, log_sys.last_checkpoint_lsn); for (auto i= size * 2; i--; page += srv_page_size) if (memcmp_aligned<8>(page + FIL_PAGE_LSN, checkpoint, 8) >= 0) /* Valid pages are not older than the log checkpoint. */ diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index a5fe4605ccf..78a0a85d438 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1567,25 +1567,6 @@ static ulint buf_do_flush_list_batch(ulint max_n, lsn_t lsn) noexcept return count; } -/** Wait until a LRU flush batch ends. */ -void buf_flush_wait_LRU_batch_end() noexcept -{ - mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); - mysql_mutex_assert_not_owner(&buf_pool.mutex); - - if (buf_pool.n_flush()) - { - tpool::tpool_wait_begin(); - thd_wait_begin(nullptr, THD_WAIT_DISKIO); - do - my_cond_wait(&buf_pool.done_flush_LRU, - &buf_pool.flush_list_mutex.m_mutex); - while (buf_pool.n_flush()); - tpool::tpool_wait_end(); - thd_wait_end(nullptr); - } -} - /** Write out dirty blocks from buf_pool.flush_list. The caller must invoke buf_dblwr.flush_buffered_writes() after releasing buf_pool.mutex. @@ -1811,20 +1792,17 @@ static ulint buf_flush_LRU(ulint max_n) noexcept # include "cache.h" #endif -/** Write checkpoint information to the log header and release mutex. -@param end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ -inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept + +inline void log_t::write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept { ut_ad(!srv_read_only_mode); - ut_ad(end_lsn >= next_checkpoint_lsn); + ut_ad(end_lsn >= checkpoint); ut_d(const lsn_t current_lsn{get_lsn()}); ut_ad(end_lsn <= current_lsn); - ut_ad(end_lsn + SIZE_OF_FILE_CHECKPOINT <= current_lsn || + ut_ad(end_lsn + SIZE_OF_FILE_CHECKPOINT + + 8 * is_encrypted() <= current_lsn || srv_shutdown_state > SRV_SHUTDOWN_INITIATED); - DBUG_PRINT("ib_log", - ("checkpoint at " LSN_PF " written", next_checkpoint_lsn)); - auto n= next_checkpoint_no; const size_t offset{(n & 1) ? CHECKPOINT_2 : CHECKPOINT_1}; static_assert(CPU_LEVEL1_DCACHE_LINESIZE >= 64, "efficiency"); @@ -1832,7 +1810,7 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept byte* c= my_assume_aligned (is_mmap() ? buf + offset : checkpoint_buf); memset_aligned(c, 0, CPU_LEVEL1_DCACHE_LINESIZE); - mach_write_to_8(my_assume_aligned<8>(c), next_checkpoint_lsn); + mach_write_to_8(my_assume_aligned<8>(c), checkpoint); mach_write_to_8(my_assume_aligned<8>(c + 8), end_lsn); mach_write_to_4(my_assume_aligned<4>(c + 60), my_crc32c(0, c, 60)); @@ -1844,7 +1822,7 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept ut_ad(!is_opened()); resizing= resize_lsn.load(std::memory_order_relaxed); - if (resizing > 1 && resizing <= next_checkpoint_lsn) + if (resizing > 1 && resizing <= checkpoint) { memcpy_aligned<64>(resize_buf + CHECKPOINT_1, c, 64); header_write(resize_buf, resizing, is_encrypted()); @@ -1856,8 +1834,6 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept #endif { ut_ad(!is_mmap()); - ut_ad(!checkpoint_pending); - checkpoint_pending= true; latch.wr_unlock(); log_write_and_flush_prepare(); resizing= resize_lsn.load(std::memory_order_relaxed); @@ -1865,7 +1841,7 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept ut_ad(write_size >= 512); ut_ad(write_size <= 4096); log.write(offset, {c, write_size}); - if (resizing > 1 && resizing <= next_checkpoint_lsn) + if (resizing > 1 && resizing <= checkpoint) { resize_log.write(CHECKPOINT_1, {c, write_size}); byte *buf= static_cast(aligned_malloc(4096, 4096)); @@ -1877,31 +1853,27 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept if (!log_write_through) ut_a(log.flush()); - latch.wr_lock(SRW_LOCK_CALL); - ut_ad(checkpoint_pending); - checkpoint_pending= false; + latch.wr_lock(); resizing= resize_lsn.load(std::memory_order_relaxed); } - ut_ad(!checkpoint_pending); next_checkpoint_no++; - const lsn_t checkpoint_lsn{next_checkpoint_lsn}; - last_checkpoint_lsn= checkpoint_lsn; + last_checkpoint_lsn= checkpoint; DBUG_PRINT("ib_log", ("checkpoint ended at " LSN_PF ", flushed to " LSN_PF, - checkpoint_lsn, get_flushed_lsn())); + checkpoint, get_flushed_lsn())); if (overwrite_warned) { sql_print_information("InnoDB: Crash recovery was broken " "between LSN=" LSN_PF " and checkpoint LSN=" LSN_PF ".", - overwrite_warned, checkpoint_lsn); + overwrite_warned, checkpoint); overwrite_warned= 0; } lsn_t resizing_completed= 0; - if (resizing > 1 && resizing <= checkpoint_lsn) + if (resizing > 1 && resizing <= checkpoint) { ut_ad(is_mmap() == !resize_flush_buf); ut_ad(is_mmap() == !resize_log.is_opened()); @@ -1978,7 +1950,7 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept log_resize_release(); if (UNIV_LIKELY(resizing <= 1)); - else if (resizing > checkpoint_lsn) + else if (resizing > checkpoint) buf_flush_ahead(resizing, false); else if (resizing_completed) ib::info() << "Resized log to " << ib::bytes_iec{resizing_completed} @@ -1989,9 +1961,8 @@ inline void log_t::write_checkpoint(lsn_t end_lsn) noexcept /** Initiate a log checkpoint, discarding the start of the log. @param oldest_lsn the checkpoint LSN -@param end_lsn log_sys.get_lsn() -@return true if success, false if a checkpoint write was already running */ -static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) noexcept +@param end_lsn log_sys.get_lsn() */ +static void log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) noexcept { ut_ad(!srv_read_only_mode); ut_ad(log_sys.latch_have_wr()); @@ -2002,14 +1973,12 @@ static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) noexcept (oldest_lsn == end_lsn && !log_sys.resize_in_progress() && oldest_lsn == log_sys.last_checkpoint_lsn + - (log_sys.is_encrypted() - ? SIZE_OF_FILE_CHECKPOINT + 8 : SIZE_OF_FILE_CHECKPOINT))) + log_sys.is_encrypted() * 8 + SIZE_OF_FILE_CHECKPOINT)) { /* Do nothing, because nothing was logged (other than a FILE_CHECKPOINT record) since the previous checkpoint. */ - do_nothing: log_sys.latch.wr_unlock(); - return true; + return; } ut_ad(!recv_no_log_write); @@ -2026,26 +1995,26 @@ static bool log_checkpoint_low(lsn_t oldest_lsn, lsn_t end_lsn) noexcept mtr_t::commit() in other threads will be blocked, and no pages can be added to buf_pool.flush_list. */ const lsn_t flush_lsn{fil_names_clear(oldest_lsn)}; - ut_ad(flush_lsn >= end_lsn + SIZE_OF_FILE_CHECKPOINT); - log_sys.latch.wr_unlock(); - log_write_up_to(flush_lsn, true); - log_sys.latch.wr_lock(SRW_LOCK_CALL); - if (log_sys.last_checkpoint_lsn >= oldest_lsn) - goto do_nothing; + ut_ad(flush_lsn >= end_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted()); + ut_ad(flush_lsn > log_sys.get_flushed_lsn()); - ut_ad(log_sys.get_flushed_lsn() >= flush_lsn); - - if (log_sys.checkpoint_pending) + if (false); +#ifdef HAVE_PMEM + else if (log_sys.is_mmap()) + log_sys.persist(flush_lsn); +#endif + else { - /* A checkpoint write is running */ log_sys.latch.wr_unlock(); - return false; + log_write_up_to(flush_lsn, true); + log_sys.latch.wr_lock(); } - log_sys.next_checkpoint_lsn= oldest_lsn; - log_sys.write_checkpoint(end_lsn); + ut_ad(oldest_lsn > log_sys.last_checkpoint_lsn); + ut_ad(log_sys.get_flushed_lsn() >= flush_lsn); - return true; + log_sys.write_checkpoint(oldest_lsn, end_lsn); } void mtr_t::write_binlog(page_id_t page_id, uint16_t offset, @@ -2072,13 +2041,10 @@ void mtr_t::write_binlog(page_id_t page_id, uint16_t offset, /** Make a checkpoint. Note that this function does not flush dirty blocks from the buffer pool: it only checks what is lsn of the oldest modification in the pool, and writes information about the lsn in -log file. Use log_make_checkpoint() to flush also the pool. -@retval true if the checkpoint was or had been made -@retval false if a checkpoint write was already running */ -static bool log_checkpoint() noexcept +log file. Use log_make_checkpoint() to flush also the pool. */ +static void log_checkpoint() noexcept { - if (recv_recovery_is_on()) - recv_sys.apply(true); + ut_ad(!recv_recovery_is_on()); #if defined HAVE_valgrind && !__has_feature(memory_sanitizer) /* The built-in scheduler in Valgrind may neglect some threads for a @@ -2091,44 +2057,68 @@ static bool log_checkpoint() noexcept fil_flush_file_spaces(); binlog_write_up_to_now(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const lsn_t end_lsn= log_sys.get_lsn(); mysql_mutex_lock(&buf_pool.flush_list_mutex); const lsn_t oldest_lsn= buf_pool.get_oldest_modification(end_lsn); // FIXME: limit oldest_lsn below binlog split write LSN mysql_mutex_unlock(&buf_pool.flush_list_mutex); - return log_checkpoint_low(oldest_lsn, end_lsn); -} - -/** Make a checkpoint. */ -ATTRIBUTE_COLD void log_make_checkpoint() noexcept -{ - buf_flush_wait_flushed(log_get_lsn()); - while (!log_checkpoint()); + log_checkpoint_low(oldest_lsn, end_lsn); } /** Wait for all dirty pages up to an LSN to be written out. -NOTE: The calling thread is not allowed to hold any buffer page latches! */ -static void buf_flush_wait(lsn_t lsn) noexcept +NOTE: The calling thread is not allowed to hold any buffer page latches! +@param lsn the checkpoint to wait for +@param checkpoint whether an empty checkpoint needs to be written */ +ATTRIBUTE_COLD void buf_flush_wait(lsn_t lsn, bool checkpoint) noexcept { + mysql_mutex_assert_owner(&buf_pool.flush_list_mutex); + ut_ad(log_sys.latch_have_wr()); + lsn_t oldest_lsn; + if (!checkpoint); + else if (lsn == log_sys.get_lsn() && + lsn == log_sys.last_checkpoint_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted()); + else if (buf_flush_sync_lsn < lsn) + goto set_target; + else + goto wake; while ((oldest_lsn= buf_pool.get_oldest_modification(lsn)) < lsn) { if (buf_flush_sync_lsn < lsn) { + set_target: buf_flush_sync_lsn= lsn; + wake: + log_sys.latch.wr_unlock(); + ut_ad(buf_page_cleaner_is_active); buf_pool.page_cleaner_set_idle(false); pthread_cond_signal(&buf_pool.do_flush_list); + MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); my_cond_wait(&buf_pool.done_flush_list, &buf_pool.flush_list_mutex.m_mutex); - oldest_lsn= buf_pool.get_oldest_modification(lsn); - if (oldest_lsn >= lsn) - break; } + else + log_sys.latch.wr_unlock(); mysql_mutex_unlock(&buf_pool.flush_list_mutex); os_aio_wait_until_no_pending_writes(false); + + log_sys.latch.wr_lock(); mysql_mutex_lock(&buf_pool.flush_list_mutex); + + if (checkpoint) + { + lsn= log_sys.get_lsn(); + if (lsn != log_sys.last_checkpoint_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted()) + { + buf_flush_sync_lsn= lsn; + log_sys.set_check_for_checkpoint(true); + goto wake; + } + } } if (oldest_lsn >= buf_flush_sync_lsn) @@ -2138,66 +2128,6 @@ static void buf_flush_wait(lsn_t lsn) noexcept } } -/** Wait until all persistent pages are flushed up to a limit. -@param sync_lsn buf_pool.get_oldest_modification(LSN_MAX) to wait for */ -ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn) noexcept -{ - ut_ad(sync_lsn); - ut_ad(sync_lsn < LSN_MAX); - ut_ad(!srv_read_only_mode); - - if (recv_recovery_is_on()) - recv_sys.apply(true); - - mysql_mutex_lock(&buf_pool.flush_list_mutex); - - if (buf_pool.get_oldest_modification(sync_lsn) < sync_lsn) - { - MONITOR_INC(MONITOR_FLUSH_SYNC_WAITS); - -#if 1 /* FIXME: remove this, and guarantee that the page cleaner serves us */ - if (UNIV_UNLIKELY(!buf_page_cleaner_is_active)) - { - do - { - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - ulint n_pages= buf_flush_list(srv_max_io_capacity, sync_lsn); - if (n_pages) - { - MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_SYNC_TOTAL_PAGE, - MONITOR_FLUSH_SYNC_COUNT, - MONITOR_FLUSH_SYNC_PAGES, n_pages); - } - os_aio_wait_until_no_pending_writes(false); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - } - while (buf_pool.get_oldest_modification(sync_lsn) < sync_lsn); - } - else -#endif - { - thd_wait_begin(nullptr, THD_WAIT_DISKIO); - tpool::tpool_wait_begin(); - buf_flush_wait(sync_lsn); - tpool::tpool_wait_end(); - thd_wait_end(nullptr); - } - } - - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - - if (UNIV_UNLIKELY(log_sys.last_checkpoint_lsn < sync_lsn)) - { - /* If the buffer pool was clean, no log write was guaranteed - to happen until now. There could be an outstanding FILE_CHECKPOINT - record from a previous fil_names_clear() call, which we must - write out before we can advance the checkpoint. */ - log_write_up_to(sync_lsn, true); - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", return;); - log_checkpoint(); - } -} - /** Initiate more eager page flushing if the log checkpoint age is too old. @param lsn buf_pool.get_oldest_modification(LSN_MAX) target @param furious true=furious flushing, false=limit to innodb_io_capacity */ @@ -2205,9 +2135,6 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept { ut_ad(!srv_read_only_mode); - if (recv_recovery_is_on()) - recv_sys.apply(true); - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", return;); Atomic_relaxed &limit= furious @@ -2223,7 +2150,7 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept { /* Request any concurrent threads to wait for this batch to complete, in log_free_check(). */ - log_sys.set_check_for_checkpoint(); + log_sys.set_check_for_checkpoint(true); /* Immediately wake up buf_flush_page_cleaner(), even when it is in the middle of a 1-second my_cond_timedwait(). */ wake: @@ -2244,7 +2171,7 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept /** Conduct checkpoint-related flushing for innodb_flush_sync=ON, and try to initiate checkpoints until the target is met. -@param lsn minimum value of buf_pool.get_oldest_modification(LSN_MAX) */ +@param lsn target checkpoint */ ATTRIBUTE_COLD ATTRIBUTE_NOINLINE static void buf_flush_sync_for_checkpoint(lsn_t lsn) noexcept { @@ -2282,6 +2209,12 @@ static void buf_flush_sync_for_checkpoint(lsn_t lsn) noexcept mysql_mutex_unlock(&buf_pool.flush_list_mutex); } + if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) + { + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "Waiting to flush the buffer pool"); + } + if (ulint n_flushed= buf_flush_list(srv_max_io_capacity, lsn)) { MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_SYNC_TOTAL_PAGE, @@ -2293,7 +2226,7 @@ static void buf_flush_sync_for_checkpoint(lsn_t lsn) noexcept fil_flush_file_spaces(); binlog_write_up_to_now(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const lsn_t newest_lsn= log_sys.get_lsn(); mysql_mutex_lock(&buf_pool.flush_list_mutex); lsn_t measure= buf_pool.get_oldest_modification(0); @@ -2301,28 +2234,31 @@ static void buf_flush_sync_for_checkpoint(lsn_t lsn) noexcept // FIXME: limit checkpoint_lsn below binlog split write LSN if (!recv_recovery_is_on() && - checkpoint_lsn > log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT) + checkpoint_lsn > log_sys.last_checkpoint_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted()) { mysql_mutex_unlock(&buf_pool.flush_list_mutex); log_checkpoint_low(checkpoint_lsn, newest_lsn); + log_sys.latch.wr_lock(); mysql_mutex_lock(&buf_pool.flush_list_mutex); - measure= buf_pool.get_oldest_modification(LSN_MAX); + measure= buf_pool.get_oldest_modification(0); } + + if (measure); + else if (srv_shutdown_state < SRV_SHUTDOWN_CLEANUP || + log_sys.get_lsn() == log_sys.last_checkpoint_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted()) + measure= LSN_MAX; else - { - log_sys.latch.wr_unlock(); - if (!measure) - measure= LSN_MAX; - } + buf_flush_sync_lsn= newest_lsn; /* After attempting log checkpoint, check if we have reached our target. */ - const lsn_t target= buf_flush_sync_lsn; - - if (measure >= target) + if (measure >= buf_flush_sync_lsn) buf_flush_sync_lsn= 0; else if (measure >= buf_flush_async_lsn) buf_flush_async_lsn= 0; + log_sys.latch.wr_unlock(); /* wake up buf_flush_wait() */ pthread_cond_broadcast(&buf_pool.done_flush_list); mysql_mutex_unlock(&buf_pool.flush_list_mutex); @@ -2588,7 +2524,7 @@ static void buf_flush_page_cleaner() noexcept mysql_mutex_lock(&buf_pool.flush_list_mutex); if (!buf_pool.need_LRU_eviction()) { - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) + if (UNIV_UNLIKELY(srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE)) break; if (buf_pool.page_cleaner_idle() && @@ -2612,29 +2548,38 @@ static void buf_flush_page_cleaner() noexcept if (!oldest_lsn) { fully_unemployed: - buf_flush_sync_lsn= 0; + if (srv_shutdown_state < SRV_SHUTDOWN_CLEANUP) + buf_flush_sync_lsn= 0; set_idle: buf_pool.page_cleaner_set_idle(true); set_almost_idle: pthread_cond_broadcast(&buf_pool.done_flush_LRU); pthread_cond_broadcast(&buf_pool.done_flush_list); - if (UNIV_UNLIKELY(srv_shutdown_state > SRV_SHUTDOWN_INITIATED)) - break; mysql_mutex_unlock(&buf_pool.flush_list_mutex); buf_dblwr.flush_buffered_writes(); do { - IF_DBUG(if (_db_keyword_(nullptr, "ib_log_checkpoint_avoid", 1) || - _db_keyword_(nullptr, "ib_log_checkpoint_avoid_hard", 1)) + if (recv_recovery_is_on()) + continue; + IF_DBUG(if (log_sys.last_checkpoint_lsn && + srv_shutdown_state < SRV_SHUTDOWN_CLEANUP && + (_db_keyword_(nullptr, "ib_log_checkpoint_avoid", 1) || + _db_keyword_(nullptr, "ib_log_checkpoint_avoid_hard", 1))) continue,); - if (!recv_recovery_is_on() && - !srv_startup_is_before_trx_rollback_phase && - srv_operation <= SRV_OPERATION_EXPORT_RESTORED) + if (log_sys.check_for_checkpoint() || + (!srv_startup_is_before_trx_rollback_phase && + srv_operation <= SRV_OPERATION_EXPORT_RESTORED)) log_checkpoint(); } while (false); + if (UNIV_UNLIKELY(srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE)) + { + mysql_mutex_lock(&buf_pool.flush_list_mutex); + break; + } + if (!buf_pool.need_LRU_eviction()) continue; mysql_mutex_lock(&buf_pool.flush_list_mutex); @@ -2649,7 +2594,8 @@ static void buf_flush_page_cleaner() noexcept goto do_furious_flush; if (oldest_lsn >= lsn_limit) { - buf_flush_sync_lsn= 0; + if (srv_shutdown_state < SRV_SHUTDOWN_CLEANUP) + buf_flush_sync_lsn= 0; pthread_cond_broadcast(&buf_pool.done_flush_list); } else if (lsn_limit > soft_lsn_limit) @@ -2670,6 +2616,9 @@ static void buf_flush_page_cleaner() noexcept buf_pool.n_flush_inc(); mysql_mutex_unlock(&buf_pool.flush_list_mutex); n= srv_max_io_capacity; + /* We must urgently perform some LRU eviction. Page writes are + only triggered by this thread, whether it is for checkpoint or + LRU eviction. First, wait for any pending writes to complete. */ os_aio_wait_until_no_pending_writes(false); mysql_mutex_lock(&buf_pool.mutex); LRU_flush: @@ -2687,7 +2636,7 @@ static void buf_flush_page_cleaner() noexcept buf_pool.page_cleaner_set_idle(false); goto set_almost_idle; } - else if (UNIV_UNLIKELY(srv_shutdown_state > SRV_SHUTDOWN_INITIATED)) + else if (UNIV_UNLIKELY(srv_shutdown_state >= SRV_SHUTDOWN_LAST_PHASE)) break; const ulint dirty_blocks= UT_LIST_GET_LEN(buf_pool.flush_list); @@ -2775,8 +2724,12 @@ static void buf_flush_page_cleaner() noexcept goto check_oldest_and_set_idle; else { - mysql_mutex_lock(&buf_pool.mutex); + /* Page writes are only triggered by this thread, whether it is + for checkpoint or LRU eviction flushing. Wait for any pending + writes of an earlier batch to complete before starting an LRU + scan to improve the chances that some blocks are clean. */ os_aio_wait_until_no_pending_writes(false); + mysql_mutex_lock(&buf_pool.mutex); } n= srv_max_io_capacity; @@ -2788,18 +2741,7 @@ static void buf_flush_page_cleaner() noexcept goto LRU_flush; } - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - - if (srv_fast_shutdown != 2) - { - buf_dblwr.flush_buffered_writes(); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - buf_flush_wait_LRU_batch_end(); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - os_aio_wait_until_no_pending_writes(false); - } - - mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(!buf_pool.n_flush()); lsn_limit= buf_flush_sync_lsn; if (UNIV_UNLIKELY(lsn_limit != 0)) { @@ -2807,6 +2749,9 @@ static void buf_flush_page_cleaner() noexcept mysql_mutex_unlock(&buf_pool.flush_list_mutex); goto furious_flush; } + ut_ad(log_sys.get_lsn_approx() == log_sys.last_checkpoint_lsn + + SIZE_OF_FILE_CHECKPOINT + 8 * log_sys.is_encrypted() || + srv_fast_shutdown == 2 || srv_read_only_mode || !srv_was_started); buf_page_cleaner_is_active= false; pthread_cond_broadcast(&buf_pool.done_flush_list); mysql_mutex_unlock(&buf_pool.flush_list_mutex); @@ -2844,76 +2789,26 @@ ATTRIBUTE_COLD void buf_flush_page_cleaner_init() noexcept std::thread(buf_flush_page_cleaner).detach(); } -/** Flush the buffer pool on shutdown. */ -ATTRIBUTE_COLD void buf_flush_buffer_pool() noexcept +/** Make a checkpoint. */ +ATTRIBUTE_COLD void log_make_checkpoint() noexcept { - ut_ad(!buf_page_cleaner_is_active); - ut_ad(!buf_flush_sync_lsn); - - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "Waiting to flush the buffer pool"); - os_aio_wait_until_no_pending_reads(false); - - mysql_mutex_lock(&buf_pool.flush_list_mutex); - - while (buf_pool.get_oldest_modification(0)) - { - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - buf_flush_list(srv_max_io_capacity); - os_aio_wait_until_no_pending_writes(false); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "Waiting to flush " ULINTPF " pages", - UT_LIST_GET_LEN(buf_pool.flush_list)); - } - - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - ut_ad(!os_aio_pending_reads()); + buf_flush_sync_batch(0, true); } -/** Synchronously flush dirty blocks during recv_sys_t::apply(). -NOTE: The calling thread is not allowed to hold any buffer page latches! */ -void buf_flush_sync_batch(lsn_t lsn) noexcept +/** Wait for the persistent data to be written out. +NOTE: The calling thread is not allowed to hold any buffer page latches! +@param lsn minimum checkpoint to wait for +@param checkpoint whether an empty checkpoint needs to be written */ +ATTRIBUTE_COLD void buf_flush_sync_batch(lsn_t lsn, bool checkpoint) noexcept { - lsn= std::max(lsn, log_get_lsn()); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - buf_flush_wait(lsn); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); -} - -/** Synchronously flush dirty blocks. -NOTE: The calling thread is not allowed to hold any buffer page latches! */ -void buf_flush_sync() noexcept -{ - if (recv_recovery_is_on()) - { - mysql_mutex_lock(&recv_sys.mutex); - recv_sys.apply(true); - mysql_mutex_unlock(&recv_sys.mutex); - } - thd_wait_begin(nullptr, THD_WAIT_DISKIO); tpool::tpool_wait_begin(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); - - for (lsn_t lsn= log_sys.get_lsn();;) - { - log_sys.latch.wr_unlock(); - mysql_mutex_lock(&buf_pool.flush_list_mutex); - buf_flush_wait(lsn); - /* Wait for the page cleaner to be idle (for log resizing at startup) */ - while (buf_flush_sync_lsn) - my_cond_wait(&buf_pool.done_flush_list, - &buf_pool.flush_list_mutex.m_mutex); - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - log_sys.latch.wr_lock(SRW_LOCK_CALL); - lsn_t new_lsn= log_sys.get_lsn(); - if (lsn == new_lsn) - break; - lsn= new_lsn; - } - + log_sys.latch.wr_lock(); + lsn= std::max(lsn, log_sys.get_lsn()); + mysql_mutex_lock(&buf_pool.flush_list_mutex); + buf_flush_wait(lsn, checkpoint); log_sys.latch.wr_unlock(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); tpool::tpool_wait_end(); thd_wait_end(nullptr); } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index cc41bc37e6b..424d2ef488c 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -934,7 +934,7 @@ bool fil_space_free(uint32_t id, bool x_latched) noexcept } if (!recv_recovery_is_on()) { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); if (space->max_lsn) { ut_d(space->max_lsn = 0); @@ -1726,7 +1726,7 @@ fil_space_t *fil_space_t::drop(uint32_t id, pfs_os_file_t *detached_handle) fil_system.named_spaces. Before we set the STOPPING_WRITES flag, another concurrent operation could have marked the tablespace dirty again. This clean-up corresponds to fil_space_free(). */ - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); ut_ad((space->pending() & ~NEEDS_FSYNC) == (STOPPING | CLOSING)); if (space->max_lsn != 0) { @@ -3170,7 +3170,7 @@ ATTRIBUTE_COLD lsn_t fil_names_clear(lsn_t lsn) noexcept auto next = std::next(it); ut_ad(it->max_lsn > 0); - if (it->max_lsn < lsn) { + if (it->max_lsn <= lsn) { /* The tablespace was last dirtied before the checkpoint LSN. Remove it from the list, so that if the tablespace is not going to be diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index 4f7ebaa3d55..f9c694e5133 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -626,16 +626,14 @@ inline dberr_t SysTablespace::read_lsn_and_check_flags() return err; } - if (srv_force_recovery != 6 + if (!log_sys.file_size && log_sys.format == log_t::FORMAT_3_23 && srv_operation == SRV_OPERATION_NORMAL - && !log_sys.next_checkpoint_lsn - && log_sys.format == log_t::FORMAT_3_23) { - - log_sys.latch.wr_lock(SRW_LOCK_CALL); - /* Prepare for possible upgrade from 0-sized ib_logfile0. */ - log_sys.next_checkpoint_lsn = mach_read_from_8( + && srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { + log_sys.latch.wr_lock(); + /* Upgrade from 0-sized ib_logfile0. */ + log_sys.last_checkpoint_lsn = mach_read_from_8( first_page + 26/*FIL_PAGE_FILE_FLUSH_LSN*/); - if (log_sys.next_checkpoint_lsn < 8204) { + if (log_sys.last_checkpoint_lsn < 8204) { /* Before MDEV-14425, InnoDB had a minimum LSN of 8192+12=8204. Likewise, mariadb-backup --prepare would create an empty ib_logfile0 @@ -645,10 +643,9 @@ inline dberr_t SysTablespace::read_lsn_and_check_flags() "empty, and LSN is unknown."); err = DB_CORRUPTION; } else { - log_sys.last_checkpoint_lsn = - recv_sys.lsn = recv_sys.file_checkpoint = - log_sys.next_checkpoint_lsn; - log_sys.set_recovered_lsn(log_sys.next_checkpoint_lsn); + recv_sys.lsn = recv_sys.file_checkpoint = + log_sys.last_checkpoint_lsn; + log_sys.set_recovered_lsn(recv_sys.lsn); log_sys.next_checkpoint_no = 0; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 4f8fa2c5a6e..2e7d9b0b83c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -110,6 +110,7 @@ bool is_update_query(enum enum_sql_command command); #include "fil0pagecompress.h" #include "ut0mem.h" #include "row0ext.h" +#include "trx0undo.h" #include "innodb_binlog.h" #include "lz4.h" @@ -244,7 +245,7 @@ static void innodb_max_purge_lag_wait_update(THD *thd, st_mysql_sys_var *, if (thd_kill_level(thd)) break; /* Adjust for purge_coordinator_state::refresh() */ - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const lsn_t last= log_sys.last_checkpoint_lsn, max_age= log_sys.max_checkpoint_age; const lsn_t lsn= log_sys.get_lsn(); @@ -583,7 +584,6 @@ mysql_pfs_key_t trx_i_s_cache_lock_key; mysql_pfs_key_t trx_purge_latch_key; mysql_pfs_key_t trx_rseg_latch_key; mysql_pfs_key_t lock_latch_key; -mysql_pfs_key_t log_latch_key; /* all_innodb_rwlocks array contains rwlocks that are performance schema instrumented if "UNIV_PFS_RWLOCK" @@ -599,7 +599,6 @@ static PSI_rwlock_info all_innodb_rwlocks[] = { &trx_purge_latch_key, "trx_purge_latch", 0 }, { &trx_rseg_latch_key, "trx_rseg_latch", 0 }, { &lock_latch_key, "lock_latch", 0 }, - { &log_latch_key, "log_latch", 0 }, { &index_tree_rw_lock_key, "index_tree_rw_lock", PSI_RWLOCK_FLAG_SX } }; # endif /* UNIV_PFS_RWLOCK */ @@ -1539,7 +1538,7 @@ static void innodb_drop_database(handlerton*, char *path) log_write_up_to(mtr.commit_lsn(), true); } - trx->free(); + trx->clear_and_free(); my_free(namebuf); } @@ -3521,7 +3520,8 @@ ha_innobase::init_table_handle_for_HANDLER(void) m_prebuilt->used_in_HANDLER = TRUE; reset_template(); - m_prebuilt->trx->bulk_insert &= TRX_DDL_BULK; + + m_prebuilt->trx->clear_dml_bulk(); } /*********************************************************************//** @@ -3578,17 +3578,36 @@ static MYSQL_SYSVAR_SIZE_T(buffer_pool_size_auto_min, innodb_buffer_pool_extent_size); #endif +#if SIZEOF_SIZE_T < 8 || defined _AIX || defined HAVE_valgrind +/* In constrained environments, innodb_buffer_pool_size_max +will default to the initial innodb_buffer_pool_size, that is, +by default, it will not be possible to increase innodb_buffer_pool_size. + +In MemorySanitizer and possibly Valgrind memcheck, any virtual memory +allocation would be backed by one or more copies of shadow bits of the +same size that could be allocated and initialized even for dummy +mappings created by mmap(2) with PROT_NONE. We do not want significant +overhead beyond the actual innodb_buffer_pool_size. */ +static constexpr size_t innodb_buffer_pool_size_max_default{0}, + innodb_buffer_pool_size_max_minimum{0}; +#else +static constexpr size_t innodb_buffer_pool_size_max_default{8ULL << 40},// 8TiB + innodb_buffer_pool_size_max_minimum{innodb_buffer_pool_extent_size}; +#endif + static MYSQL_SYSVAR_SIZE_T(buffer_pool_size_max, buf_pool.size_in_bytes_max, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Maximum innodb_buffer_pool_size", - nullptr, nullptr, 0, 0, + nullptr, nullptr, + innodb_buffer_pool_size_max_default, + innodb_buffer_pool_size_max_minimum, size_t(-ssize_t(innodb_buffer_pool_extent_size)), innodb_buffer_pool_extent_size); static MYSQL_SYSVAR_UINT(log_write_ahead_size, log_sys.write_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Redo log write size to avoid read-on-write; must be a power of two", - nullptr, nullptr, 512, 512, 4096, 1); + nullptr, nullptr, 512, 512, log_sys.WRITE_SIZE_MAX, 1); #ifdef BTR_CUR_HASH_ADAPT @@ -3705,11 +3724,10 @@ static int innodb_init_params() min= ut_calc_align (buf_pool.blocks_in_bytes(BUF_LRU_MIN_LEN + BUF_LRU_MIN_LEN / 4), 1U << 20); - size_t innodb_buffer_pool_size= buf_pool.size_in_bytes_requested; + const size_t innodb_buffer_pool_size= buf_pool.size_in_bytes_requested; - /* With large pages, buffer pool can't grow or shrink. */ - if (!buf_pool.size_in_bytes_max || my_use_large_pages || - innodb_buffer_pool_size > buf_pool.size_in_bytes_max) + if (innodb_buffer_pool_size > buf_pool.size_in_bytes_max || + my_use_large_pages /* large_pages=ON fixes innodb_buffer_pool_size */) buf_pool.size_in_bytes_max= ut_calc_align(innodb_buffer_pool_size, innodb_buffer_pool_extent_size); @@ -4490,7 +4508,7 @@ static bool end_of_statement(trx_t *trx) noexcept undo_no_t savept= 0; trx->rollback(&savept); /* MariaDB will roll back the entire transaction. */ - trx->bulk_insert&= TRX_DDL_BULK; + trx->clear_dml_bulk(); trx->last_stmt_start= 0; return true; } @@ -4737,7 +4755,7 @@ checkpoint complete when we have flushed the redo log. If we have already flushed all relevant redo log, we notify immediately.*/ static void innodb_log_flush_request(void *cookie) noexcept { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); lsn_t flush_lsn= log_sys.get_flushed_lsn(); /* Load lsn relaxed after flush_lsn was loaded from the same cache line */ const lsn_t lsn= log_sys.get_lsn(); @@ -5083,6 +5101,7 @@ Ensure that indexed virtual columns will be computed. Needs to be done for indexes that are being added with inplace ALTER in a different thread, because from the server point of view these columns are not yet indexed. +Also needed if the primary key is being updated. */ void ha_innobase::column_bitmaps_signal() { @@ -5090,7 +5109,25 @@ void ha_innobase::column_bitmaps_signal() return; dict_index_t* clust_index= dict_table_get_first_index(m_prebuilt->table); - if (!clust_index->online_log) + bool is_online_log= clust_index->online_log; + + /* + Check if the clustered index is being updated. + If so, it is necessary to compute virtual columns that are part of + secondary indexes, to be able to re-compute those indexes. + */ + bool upd_pk= false; + for (uint j= 0; j < clust_index->n_user_defined_cols; ++j) + { + dict_col_t *col= clust_index->fields[j].col; + if (bitmap_is_set(table->write_set, static_cast(col->ind))) + { + upd_pk= 1; + break; + } + } + + if (!is_online_log && !upd_pk) return; uint num_v= 0; @@ -5101,7 +5138,7 @@ void ha_innobase::column_bitmaps_signal() dict_col_t *col= &m_prebuilt->table->v_cols[num_v].m_col; if (col->ord_part || - (dict_index_is_online_ddl(clust_index) && + (is_online_log && dict_index_is_online_ddl(clust_index) && row_log_col_is_indexed(clust_index, num_v))) table->mark_virtual_column_with_deps(table->vfield[j]); num_v++; @@ -15859,6 +15896,15 @@ bool ha_innobase::referenced_by_foreign_key() const noexcept return !empty; } +inline void trx_t::reset_and_truncate_undo() noexcept +{ + ut_ad(undo_no <= 1); + ut_ad(mod_tables.size() <= 1); + mod_tables.clear(); + undo_no= 0; + trx_undo_try_truncate(this); +} + /*******************************************************************//** Tells something additional to the handler about how to do things. @return 0 or error number */ @@ -15888,7 +15934,7 @@ ha_innobase::extra( stmt_boundary: trx->bulk_insert_apply(); trx->end_bulk_insert(*m_prebuilt->table); - trx->bulk_insert &= TRX_DDL_BULK; + trx->clear_dml_bulk(); break; case HA_EXTRA_NO_KEYREAD: (void)check_trx_exists(thd); @@ -15932,11 +15978,25 @@ ha_innobase::extra( break; } goto stmt_boundary; - case HA_EXTRA_BEGIN_ALTER_COPY: + case HA_EXTRA_BEGIN_ALTER_IGNORE_COPY: + case HA_EXTRA_BEGIN_COPY: trx = check_trx_exists(thd); - m_prebuilt->table->skip_alter_undo = 1; - if (m_prebuilt->table->is_temporary() - || !m_prebuilt->table->versioned_by_id()) { + static_assert(int{HA_EXTRA_BEGIN_ALTER_IGNORE_COPY} == + int{HA_EXTRA_BEGIN_COPY} + 1, ""); + static_assert(int{dict_table_t::NO_UNDO} + 1 == + int{dict_table_t::IGNORE_UNDO}, ""); + if (m_prebuilt->table->is_temporary()) { + m_prebuilt->table->skip_alter_undo = + (HA_EXTRA_BEGIN_ALTER_IGNORE_COPY + - operation + dict_table_t::NORMAL_UNDO) & 1; + break; + } + + m_prebuilt->table->skip_alter_undo = + (operation - HA_EXTRA_BEGIN_COPY + + dict_table_t::NO_UNDO) & 3; + + if (!m_prebuilt->table->versioned_by_id()) { break; } ut_ad(trx == m_prebuilt->trx); @@ -15945,15 +16005,24 @@ ha_innobase::extra( const_cast(m_prebuilt->table), 0) .first->second.set_versioned(0); break; - case HA_EXTRA_END_ALTER_COPY: + case HA_EXTRA_END_COPY: + { trx = check_trx_exists(thd); - if (!m_prebuilt->table->skip_alter_undo) { + const unsigned alter_undo = m_prebuilt->table->skip_alter_undo; + if (!alter_undo) { /* This could be invoked inside INSERT...SELECT. We do not want any extra log writes, because they could cause a severe performance regression. */ break; } - m_prebuilt->table->skip_alter_undo = 0; + + if (alter_undo == dict_table_t::IGNORE_UNDO) { + trx->reset_and_truncate_undo(); + } + + m_prebuilt->table->skip_alter_undo = + dict_table_t::NORMAL_UNDO; + if (dberr_t err= trx->bulk_insert_apply()) { trx->rollback(); return convert_error_code_to_mysql( @@ -15962,7 +16031,7 @@ ha_innobase::extra( } trx->end_bulk_insert(*m_prebuilt->table); - trx->bulk_insert &= TRX_DML_BULK; + trx->clear_ddl_bulk(); if (!m_prebuilt->table->is_temporary() && !high_level_read_only) { /* During copy_data_between_tables(), InnoDB only @@ -15977,16 +16046,22 @@ ha_innobase::extra( because no undo log records were generated. This log write will also be unnecessarily executed during CREATE...SELECT, which is the other caller of - handler::extra(HA_EXTRA_BEGIN_ALTER_COPY). */ + handler::extra(HA_EXTRA_ALTER_COPY). */ log_buffer_flush_to_disk(); } alter_stats_rebuild(m_prebuilt->table, trx); break; - case HA_EXTRA_ABORT_ALTER_COPY: + } + case HA_EXTRA_ABORT_COPY: + /* Abort the ALTER COPY operation. For ALTER IGNORE, + this prevents undo logs from being added to the + purge thread, allowing proper cleanup of the + temporary undo state. */ if (m_prebuilt->table->skip_alter_undo && !m_prebuilt->table->is_temporary()) { trx = check_trx_exists(ha_thd()); - m_prebuilt->table->skip_alter_undo = 0; + m_prebuilt->table->skip_alter_undo = + dict_table_t::NORMAL_UNDO; trx->rollback(); return(HA_ERR_ROLLBACK); } @@ -16276,7 +16351,7 @@ ha_innobase::external_lock( if (!trx->bulk_insert) { break; } - trx->bulk_insert &= TRX_DDL_BULK; + trx->clear_dml_bulk(); trx->last_stmt_start = trx->undo_no; } @@ -18489,7 +18564,7 @@ checkpoint_now_set(THD* thd, st_mysql_sys_var*, void*, const void *save) mysql_mutex_unlock(&LOCK_global_system_variables); while (!thd_kill_level(thd)) { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); lsn_t cp= log_sys.last_checkpoint_lsn.load(std::memory_order_relaxed), lsn= log_sys.get_lsn(); log_sys.latch.wr_unlock(); @@ -18520,7 +18595,7 @@ buf_flush_list_now_set(THD*, st_mysql_sys_var*, void*, const void* save) os_aio_wait_until_no_pending_writes(true); } else - buf_flush_sync(); + buf_flush_sync_batch(0, false); mysql_mutex_lock(&LOCK_global_system_variables); } @@ -18747,7 +18822,7 @@ static void innodb_log_file_size_update(THD *thd, st_mysql_sys_var*, mysql_mutex_unlock(&buf_pool.flush_list_mutex); if (!resizing || !log_sys.resize_running(thd)) break; - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); while (resizing > log_sys.get_lsn()) { ut_ad(!log_sys.is_mmap()); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1a1086d9389..a3550491162 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1559,9 +1559,8 @@ static bool alter_options_need_rebuild( const ha_table_option_struct& alt_opt= *ha_alter_info->create_info->option_struct; - /* Allow an instant change to enable page_compressed, - and any change of page_compression_level. */ - if ((!alt_opt.page_compressed && opt.page_compressed) + /* Allow an instant change of page_compression_level. */ + if ((alt_opt.page_compressed != opt.page_compressed) || alt_opt.encryption != opt.encryption || alt_opt.encryption_key_id != opt.encryption_key_id) { return(true); @@ -2223,6 +2222,8 @@ ha_innobase::check_if_supported_inplace_alter( { DBUG_ENTER("check_if_supported_inplace_alter"); + ha_alter_info->file_per_table= !!srv_file_per_table; + if ((ha_alter_info->handler_flags & INNOBASE_ALTER_VERSIONED_REBUILD) && altered_table->versioned(VERS_TIMESTAMP)) { @@ -2337,8 +2338,10 @@ innodb_instant_alter_column_allowed_reason: switch (ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE) { case ALTER_OPTIONS: - if ((srv_file_per_table && !m_prebuilt->table->space_id) - || alter_options_need_rebuild(ha_alter_info, *option_struct)) { + if ((ha_alter_info->file_per_table && + !m_prebuilt->table->space_id) + || alter_options_need_rebuild(ha_alter_info, + *option_struct)) { reason_rebuild = my_get_err_msg( ER_ALTER_OPERATION_TABLE_OPTIONS_NEED_REBUILD); ha_alter_info->unsupported_reason = reason_rebuild; @@ -6601,7 +6604,7 @@ prepare_inplace_alter_table_dict( create_table_info_t info(ctx->prebuilt->trx->mysql_thd, altered_table, ha_alter_info->create_info, - srv_file_per_table); + ha_alter_info->file_per_table); /* The primary index would be rebuilt if a FTS Doc ID column is to be added, and the primary index definition @@ -8028,7 +8031,7 @@ ha_innobase::prepare_inplace_alter_table( create_table_info_t info(m_user_thd, altered_table, ha_alter_info->create_info, - srv_file_per_table); + ha_alter_info->file_per_table); info.set_tablespace_type(indexed_table->space != fil_system.sys_space); @@ -8616,15 +8619,6 @@ field_changed: DBUG_RETURN(true); } - if ((ha_alter_info->handler_flags & ALTER_OPTIONS) - && ctx->page_compression_level - && !ctx->old_table->not_redundant()) { - my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), - table_type(), - "PAGE_COMPRESSED=1 ROW_FORMAT=REDUNDANT"); - DBUG_RETURN(true); - } - if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA) && alter_templ_needs_rebuild(altered_table, ha_alter_info, ctx->new_table) @@ -8783,9 +8777,7 @@ alter_templ_needs_rebuild( const Alter_inplace_info* ha_alter_info, const dict_table_t* table) { - ulint i = 0; - - for (Field** fp = altered_table->field; *fp; fp++, i++) { + for (Field** fp = altered_table->field; *fp; fp++) { for (const Create_field& cf : ha_alter_info->alter_info->create_list) { for (ulint j=0; j < table->n_cols; j++) { @@ -9651,13 +9643,11 @@ innobase_rename_columns_try( trx_t* trx, const char* table_name) { - uint i = 0; - DBUG_ASSERT(ctx->need_rebuild()); DBUG_ASSERT(ha_alter_info->handler_flags & ALTER_COLUMN_NAME); - for (Field** fp = table->field; *fp; fp++, i++) { + for (Field** fp = table->field; *fp; fp++) { if (!((*fp)->flags & FIELD_IS_RENAMED)) { continue; } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index f2c4f9bc0cd..31bcd6f863b 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -1028,7 +1028,7 @@ dberr_t ibuf_upgrade_needed() mtr_t mtr{nullptr}; mtr.start(); mtr.x_lock_space(fil_system.sys_space); - dberr_t err; + dberr_t err= DB_SUCCESS; const buf_block_t *header_page= recv_sys.recover(ibuf_header, &mtr, &err); if (!header_page) diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index cd207bd0c1b..a7b4d589665 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -378,10 +378,6 @@ buf_print_io( /** Refresh the statistics used to print per-second averages. */ void buf_refresh_io_stats() noexcept; -/** Invalidate all pages in the buffer pool. -All pages must be in a replaceable state (not modified or latched). */ -void buf_pool_invalidate() noexcept; - /*======================================================================== --------------------------- LOWER LEVEL ROUTINES ------------------------- =========================================================================*/ diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 5d01d38ba21..65afbdad181 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -81,11 +81,10 @@ bool buf_flush_list_space(fil_space_t *space, ulint *n_flushed= nullptr) noexcept MY_ATTRIBUTE((warn_unused_result)); -/** Wait until a LRU flush batch ends. */ -void buf_flush_wait_LRU_batch_end() noexcept; /** Wait until all persistent pages are flushed up to a limit. -@param sync_lsn buf_pool.get_oldest_modification(LSN_MAX) to wait for */ -ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn) noexcept; +@param sync_lsn minimum checkpoint +@param checkpoint whether an empty checkpoint needs to be written */ +ATTRIBUTE_COLD void buf_flush_wait(lsn_t sync_lsn, bool checkpoint) noexcept; /** Initiate more eager page flushing if the log checkpoint age is too old. @param lsn buf_pool.get_oldest_modification(LSN_MAX) target @param furious true=furious flushing, false=limit to innodb_io_capacity */ @@ -94,18 +93,13 @@ ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious) noexcept; /** Initialize page_cleaner. */ ATTRIBUTE_COLD void buf_flush_page_cleaner_init() noexcept; -/** Flush the buffer pool on shutdown. */ -ATTRIBUTE_COLD void buf_flush_buffer_pool() noexcept; - #ifdef UNIV_DEBUG /** Validate the flush list. */ void buf_flush_validate() noexcept; #endif /* UNIV_DEBUG */ -/** Synchronously flush dirty blocks during recv_sys_t::apply(). -NOTE: The calling thread is not allowed to hold any buffer page latches! */ -void buf_flush_sync_batch(lsn_t lsn) noexcept; - -/** Synchronously flush dirty blocks. -NOTE: The calling thread is not allowed to hold any buffer page latches! */ -void buf_flush_sync() noexcept; +/** Wait for the persistent data to be written out. +NOTE: The calling thread is not allowed to hold any buffer page latches! +@param lsn minimum checkpoint to wait for +@param checkpoint whether an empty checkpoint needs to be written */ +ATTRIBUTE_COLD void buf_flush_sync_batch(lsn_t lsn, bool checkpoint) noexcept; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 87f034f3178..260a37e4635 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -2223,12 +2223,25 @@ public: Use DICT_TF2_FLAG_IS_SET() to parse this flag. */ unsigned flags2:DICT_TF2_BITS; - /** TRUE if the table is an intermediate table during copy alter - operation or a partition/subpartition which is required for copying - data and skip the undo log for insertion of row in the table. - This variable will be set and unset during extra(), or during the - process of altering partitions */ - unsigned skip_alter_undo:1; + /** Undo log handling modes for ALTER [IGNORE] TABLE...ALGORITHM=COPY */ + static constexpr unsigned NORMAL_UNDO = 0; + /** Never writes row-level undo log records */ + static constexpr unsigned NO_UNDO = 1; + /** For ALTER IGNORE TABLE...ALGORITHM=COPY, this enables rewriting + old insert undo blocks to maintain only the latest insert undo log. */ + static constexpr unsigned IGNORE_UNDO = 2; + + /** Mode for handling undo logs during ALTER TABLE...ALGORITHM=COPY + operations. This will not be consulted in + ha_innobase::inplace_alter_table(); Set during copy alter operations + or partition/subpartition operations. When set, controls undo log + behavior for row operations in the table. This variable is set and + unset during extra(), or during the process of altering partitions + + All reads of bit-fields in the same word must be protected by + at least a shared MDL on the table, and all writes must be + protected by an exclusive MDL. */ + unsigned skip_alter_undo:2; /** whether this is in a single-table tablespace and the .ibd file is believed to be missing or page decryption failed and page is diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 11b034bb1a4..e3a3c177736 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -75,8 +75,9 @@ ATTRIBUTE_COLD void log_write_and_flush() noexcept; /** Make a checkpoint */ ATTRIBUTE_COLD void log_make_checkpoint() noexcept; -/** Make a checkpoint at the latest lsn on shutdown. */ -ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown() noexcept; +/** Make a checkpoint at the latest lsn on shutdown. +@return the shutdown LSN */ +ATTRIBUTE_COLD lsn_t logs_empty_and_mark_files_at_shutdown() noexcept; /******************************************************//** Prints info of the log. */ @@ -190,17 +191,22 @@ private: public: /** innodb_log_buffer_size (usable append_prepare() size in bytes) */ unsigned buf_size; + /** set when there may be need to initiate a log checkpoint. + This must hold if lsn - last_checkpoint_lsn > max_checkpoint_age. */ + std::atomic need_checkpoint; + /** next checkpoint number (protected by latch.wr_lock()) */ + byte next_checkpoint_no; /** log file size in bytes, including the header */ lsn_t file_size; -#ifdef LOG_LATCH_DEBUG - typedef srw_lock_debug log_rwlock; +#if defined LOG_LATCH_DEBUG && defined UNIV_DEBUG + typedef srw_lock_debug_simple log_rwlock; bool latch_have_wr() const { return latch.have_wr(); } bool latch_have_rd() const { return latch.have_rd(); } bool latch_have_any() const { return latch.have_any(); } #else - typedef srw_lock log_rwlock; + typedef srw_lock_low log_rwlock; # ifndef UNIV_DEBUG # elif defined SUX_LOCK_GENERIC bool latch_have_wr() const { return true; } @@ -234,13 +240,6 @@ public: In write_buf(), buf and flush_buf may be swapped */ byte *flush_buf; - /** set when there may be need to initiate a log checkpoint. - This must hold if lsn - last_checkpoint_lsn > max_checkpoint_age. */ - std::atomic need_checkpoint; - /** whether a checkpoint is pending; protected by latch.wr_lock() */ - Atomic_relaxed checkpoint_pending; - /** next checkpoint number (protected by latch.wr_lock()) */ - byte next_checkpoint_no; /** Log sequence number when a log file overwrite (broken crash recovery) was noticed. Protected by latch.wr_lock(). */ lsn_t overwrite_warned; @@ -249,8 +248,6 @@ public: Atomic_relaxed last_checkpoint_lsn; /** The log writer (protected by latch.wr_lock()) */ lsn_t (*writer)() noexcept; - /** next checkpoint LSN (protected by latch.wr_lock()) */ - lsn_t next_checkpoint_lsn; /** Log file */ log_file_t log; @@ -272,6 +269,8 @@ private: public: /** current innodb_log_write_ahead_size */ uint write_size; + /** maximum write_size */ + static constexpr uint WRITE_SIZE_MAX{4096}; /** format of the redo log: e.g., FORMAT_10_8 */ uint32_t format; /** whether the memory-mapped interface is enabled for the log */ @@ -461,11 +460,11 @@ public: void persist(lsn_t lsn) noexcept; #endif - bool check_for_checkpoint() const + bool check_for_checkpoint() const noexcept { return UNIV_UNLIKELY(need_checkpoint.load(std::memory_order_relaxed)); } - void set_check_for_checkpoint(bool need= true) + void set_check_for_checkpoint(bool need) noexcept { need_checkpoint.store(need, std::memory_order_relaxed); } @@ -548,8 +547,12 @@ public: } /** Write checkpoint information and invoke latch.wr_unlock(). + @param checkpoint the new checkpoint LSN @param end_lsn start LSN of the FILE_CHECKPOINT mini-transaction */ - inline void write_checkpoint(lsn_t end_lsn) noexcept; + inline void write_checkpoint(lsn_t checkpoint, lsn_t end_lsn) noexcept; + + /** Wait for write_checkpoint() if necessary. */ + ATTRIBUTE_COLD void checkpoint_margin() noexcept; /** Variations of write_buf() */ enum resizing_and_latch { diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index f87ca043697..7de6a431329 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -44,11 +44,6 @@ ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result)) @return whether the page was recovered correctly */ bool recv_recover_page(fil_space_t* space, buf_page_t* bpage); -/** Read the latest checkpoint information from log file -and store it in log_sys.next_checkpoint and recv_sys.file_checkpoint -@return error code or DB_SUCCESS */ -dberr_t recv_recovery_read_checkpoint(); - /** Start recovering from a redo log checkpoint. of first system tablespace page @return error code or DB_SUCCESS */ @@ -230,7 +225,10 @@ public: /** whether we are applying redo log records during crash recovery. This can be cleared when holding mutex, or when pages.empty() and - we are holding exclusive log_sys.latch. */ + we are holding exclusive log_sys.latch. When this is set, + buf_flush_page_cleaner() will not invoke log_checkpoint_low(), + buf_pool.flush_list may be unsorted by buf_page_t::oldest_modification(), + and garbage_collect() replaces buf_pool_t::running_out(). */ Atomic_relaxed recovery_on= false; /** whether recv_recover_page(), invoked from buf_page_t::read_complete(), should apply log records*/ diff --git a/storage/innobase/include/mach0data.inl b/storage/innobase/include/mach0data.inl index e0824204560..8ebfb454355 100644 --- a/storage/innobase/include/mach0data.inl +++ b/storage/innobase/include/mach0data.inl @@ -30,6 +30,7 @@ Created 11/28/1995 Heikki Tuuri #include "mtr0types.h" #include "ut0byte.h" +#include "my_byteorder.h" /*******************************************************//** The following function is used to store data in one byte. */ @@ -63,8 +64,8 @@ mach_write_to_2( ut_ad((n & ~0xFFFFUL) == 0); #endif - b[0] = (byte)(n >> 8); - b[1] = (byte)(n); + uint16_t v = my_htobe16(uint16_t(n)); + memcpy(b, &v, 2); } /** The following function is used to fetch data from one byte. @@ -87,7 +88,9 @@ uint16_t mach_read_from_2( const byte* b) { - return(uint16_t(uint16_t(b[0]) << 8 | b[1])); + uint16_t v; + memcpy(&v, b, 2); + return my_betoh16(v); } #ifndef UNIV_INNOCHECKSUM @@ -135,8 +138,7 @@ mach_write_to_3( { ut_ad((n & ~0xFFFFFFUL) == 0); - b[0] = (byte)(n >> 16); - b[1] = (byte)(n >> 8); + mach_write_to_2(b, n >> 8); b[2] = (byte)(n); } @@ -149,10 +151,7 @@ uint32_t mach_read_from_3( const byte* b) { - return( (static_cast(b[0]) << 16) - | (static_cast(b[1]) << 8) - | static_cast(b[2]) - ); + return (uint32_t(mach_read_from_2(b)) << 8) | uint32_t(b[2]); } #endif /* !UNIV_INNOCHECKSUM */ @@ -166,10 +165,8 @@ mach_write_to_4( byte* b, /*!< in: pointer to four bytes where to store */ ulint n) /*!< in: ulint integer to be stored */ { - b[0] = (byte)(n >> 24); - b[1] = (byte)(n >> 16); - b[2] = (byte)(n >> 8); - b[3] = (byte) n; + uint32_t v = my_htobe32(uint32_t(n)); + memcpy(b, &v, 4); } /** The following function is used to fetch data from 4 consecutive @@ -181,11 +178,9 @@ uint32_t mach_read_from_4( const byte* b) { - return( (static_cast(b[0]) << 24) - | (static_cast(b[1]) << 16) - | (static_cast(b[2]) << 8) - | static_cast(b[3]) - ); + uint32_t v; + memcpy(&v, b, 4); + return my_betoh32(v); } #ifndef UNIV_INNOCHECKSUM @@ -343,8 +338,8 @@ mach_write_to_8( void* b, /*!< in: pointer to 8 bytes where to store */ ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { - mach_write_to_4(static_cast(b), (ulint) (n >> 32)); - mach_write_to_4(static_cast(b) + 4, (ulint) n); + uint64_t v = my_htobe64(n); + memcpy(b, &v, 8); } #endif /* !UNIV_INNOCHECKSUM */ @@ -359,13 +354,10 @@ mach_read_from_8( /*=============*/ const byte* b) /*!< in: pointer to 8 bytes */ { - ib_uint64_t u64; + uint64_t v; - u64 = mach_read_from_4(b); - u64 <<= 32; - u64 |= mach_read_from_4(b + 4); - - return(u64); + memcpy(&v, b, 8); + return my_betoh64(v); } #ifndef UNIV_INNOCHECKSUM @@ -723,7 +715,7 @@ mach_read_from_2_little_endian( /*===========================*/ const byte* buf) /*!< in: from where to read */ { - return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8)); + return uint2korr(buf); } /*********************************************************//** @@ -736,13 +728,7 @@ mach_write_to_2_little_endian( ulint n) /*!< in: unsigned long int to write */ { ut_ad(n < 256 * 256); - - *dest = (byte)(n & 0xFFUL); - - n = n >> 8; - dest++; - - *dest = (byte)(n & 0xFFUL); + int2store(dest, n); } /*********************************************************//** diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h index c18cf1ceb63..e562458722c 100644 --- a/storage/innobase/include/srv0start.h +++ b/storage/innobase/include/srv0start.h @@ -88,9 +88,6 @@ srv_get_encryption_data_filename( char* filename, ulint max_len); -/** Log sequence number at shutdown */ -extern lsn_t srv_shutdown_lsn; - /** TRUE if the server is being started */ extern bool srv_is_being_started; /** TRUE if the server is being started, before rolling back any diff --git a/storage/innobase/include/srw_lock.h b/storage/innobase/include/srw_lock.h index cf771eda3cf..a7088c5bef3 100644 --- a/storage/innobase/include/srw_lock.h +++ b/storage/innobase/include/srw_lock.h @@ -656,4 +656,54 @@ public: /** @return whether this thread is holding rd_lock() or wr_lock() */ bool have_any() const noexcept; }; + +# ifndef LOG_LATCH_DEBUG +# elif !defined UNIV_PFS_RWLOCK +typedef srw_lock_debug srw_lock_debug_simple; +# else +class srw_lock_debug_simple : private ssux_lock_impl +{ + /** The owner of the exclusive lock (0 if none) */ + std::atomic writer; + /** Protects readers */ + mutable srw_mutex readers_lock; + /** Threads that hold the lock in shared mode */ + std::atomic*> readers; + + /** Register a read lock. */ + void readers_register() noexcept; + +public: + void init() noexcept; + void destroy() noexcept; + +#ifndef SUX_LOCK_GENERIC + /** @return whether any lock may be held by any thread */ + bool is_locked_or_waiting() const noexcept + { return ssux_lock_impl::is_locked_or_waiting(); } + /** @return whether an exclusive lock may be held by any thread */ + bool is_write_locked() const noexcept + { return ssux_lock_impl::is_write_locked(); } +#endif + + /** Acquire an exclusive lock */ + void wr_lock() noexcept; + /** @return whether an exclusive lock was acquired */ + bool wr_lock_try() noexcept; + /** Release after wr_lock() */ + void wr_unlock() noexcept; + /** Acquire a shared lock */ + void rd_lock() noexcept; + /** @return whether a shared lock was acquired */ + bool rd_lock_try() noexcept; + /** Release after rd_lock() */ + void rd_unlock() noexcept; + /** @return whether this thread is between rd_lock() and rd_unlock() */ + bool have_rd() const noexcept; + /** @return whether this thread is between wr_lock() and wr_unlock() */ + bool have_wr() const noexcept; + /** @return whether this thread is holding rd_lock() or wr_lock() */ + bool have_any() const noexcept; +}; +# endif #endif diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 2063f1179da..26fe376ec96 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1211,6 +1211,35 @@ public: return bulk_insert == type ? bulk_insert_apply_low(): DB_SUCCESS; } + /** This function used only during ALTER IGNORE TABLE command. + Reset the undo no and remove the undo log from transaction. + By doing this, InnoDB doesn't add any undo logs to purge queue + during transaction commit */ + inline void reset_and_truncate_undo() noexcept; + + /** Clear TRX_DML_BULK, retaining TRX_DDL_BULK if it was set. */ + void clear_dml_bulk() noexcept + { + static_assert(TRX_NO_BULK == 0, ""); + static_assert(TRX_DML_BULK == 2, ""); + static_assert(TRX_DDL_BULK == 3, ""); + static_assert((TRX_DML_BULK & 1) == 0, ""); + ut_ad(bulk_insert != 1); + bulk_insert= unsigned( + (bulk_insert & (((bulk_insert ^ bulk_insert << 1) & 2 >> 1) * 3)) & 3); + } + + /** Clear TRX_DDL_BULK, retaining TRX_DML_BULK if it was set. */ + void clear_ddl_bulk() noexcept + { + static_assert(TRX_NO_BULK == 0, ""); + static_assert(TRX_DML_BULK == 2, ""); + static_assert(TRX_DDL_BULK == 3, ""); + static_assert((TRX_DML_BULK & 1) == 0, ""); + ut_ad(bulk_insert != 1); + bulk_insert= unsigned((bulk_insert ^ ((bulk_insert & 1) * 3)) & 3); + } + private: /** Apply the buffered bulk inserts. */ dberr_t bulk_insert_apply_low(); diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index 2da83a226d0..6fde1e831e5 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -69,9 +69,9 @@ enum trx_state_t { enum trx_bulk_insert { TRX_NO_BULK, /** bulk insert is being executed during DML */ - TRX_DML_BULK, + TRX_DML_BULK = 2, /** bulk insert is being executed in copy_data_between_tables() */ - TRX_DDL_BULK + TRX_DDL_BULK = 3 }; /** Memory objects */ diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index 5d998c8da66..0cd1ed7cfa7 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -265,6 +265,8 @@ struct trx_undo_t { uint16_t top_offset; /*!< offset of the latest undo record, i.e., the topmost element in the undo log if we think of it as a stack */ + uint16_t old_offset; /*!< previous undo record offset + for ALTER IGNORE */ undo_no_t top_undo_no; /*!< undo number of the latest record (IB_ID_MAX if the undo log is empty) */ buf_block_t* guess_block; /*!< guess for the buffer block where diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 6193b290c88..9962c81fe97 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -496,7 +496,6 @@ extern mysql_pfs_key_t index_tree_rw_lock_key; extern mysql_pfs_key_t index_online_log_key; extern mysql_pfs_key_t trx_sys_rw_lock_key; extern mysql_pfs_key_t lock_latch_key; -extern mysql_pfs_key_t log_latch_key; extern mysql_pfs_key_t trx_rseg_latch_key; # endif /* UNIV_PFS_RWLOCK */ #endif /* HAVE_PSI_INTERFACE */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index f275b33ea7b..bc77da28875 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1697,7 +1697,8 @@ static void lock_rec_add_to_queue(const conflicting_lock_info &c_lock_info, unsigned type_mode, const hash_cell_t &cell, const page_id_t id, const page_t *page, ulint heap_no, dict_index_t *index, - trx_t *trx, bool caller_owns_trx_mutex) + trx_t *trx, bool caller_owns_trx_mutex, + bool report_waits= false) { ut_d(lock_sys.hash_get(type_mode).assert_locked(id)); ut_ad(xtest() || caller_owns_trx_mutex == trx->mutex_is_owner()); @@ -1758,6 +1759,7 @@ static void lock_rec_add_to_queue(const conflicting_lock_info &c_lock_info, const bool bypass_mode = !is_supremum && lock_t::is_rec_exclusive_not_gap(type_mode); bool has_s_lock_or_stronger = false; + bool do_create= false; for (lock_t* lock = first_lock;;) { if (!lock_rec_get_nth_bit(lock, heap_no)) goto cont; @@ -1776,12 +1778,25 @@ static void lock_rec_add_to_queue(const conflicting_lock_info &c_lock_info, else if (lock->is_waiting() && (!bypass_mode || !has_s_lock_or_stronger || !lock->is_gap())) + { +#ifdef HAVE_REPLICATION + if (report_waits) + { + do_create= true; + thd_rpl_deadlock_check(lock->trx->mysql_thd, + trx->mysql_thd); + } + else +#endif goto create; + } cont: if (!(lock = lock_rec_get_next_on_page(lock))) { break; } } + if (do_create) + goto create; const lock_t *bypassed = c_lock_info.insert_after ? lock_rec_get_next(heap_no, c_lock_info.insert_after) @@ -1969,7 +1984,8 @@ lock_rec_lock( { /* Set the requested lock on the record. */ lock_rec_add_to_queue(c_lock_info, mode, g.cell(), id, - block->page.frame, heap_no, index, trx, true); + block->page.frame, heap_no, index, trx, true, + true); err= DB_SUCCESS_LOCKED_REC; } } diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 7d7f74a98eb..9891e1c8ec4 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -91,12 +91,12 @@ void log_t::create() noexcept ut_ad(this == &log_sys); ut_ad(!is_initialised()); - latch.SRW_LOCK_INIT(log_latch_key); + latch.init(); write_lsn_offset= 0; /* LSN 0 and 1 are reserved; @see buf_page_t::oldest_modification_ */ base_lsn.store(FIRST_LSN, std::memory_order_relaxed); flushed_to_disk_lsn.store(FIRST_LSN, std::memory_order_relaxed); - need_checkpoint.store(true, std::memory_order_relaxed); + need_checkpoint.store(false, std::memory_order_relaxed); write_lsn= FIRST_LSN; ut_ad(!checkpoint_buf); @@ -112,8 +112,6 @@ void log_t::create() noexcept log_capacity= 0; max_modified_age_async= 0; max_checkpoint_age= 0; - next_checkpoint_lsn= 0; - checkpoint_pending= false; ut_ad(is_initialised()); } @@ -287,9 +285,8 @@ remap: if (!stat("/dev/shm", &st)) { is_pmem= st.st_dev == st_dev; - if (!is_pmem) - return ptr; /* MAP_FAILED */ - goto remap; + if (is_pmem) + goto remap; } } } @@ -506,7 +503,7 @@ void log_t::close_file(bool really_close) noexcept /** @return the current log sequence number (may be stale) */ lsn_t log_get_lsn() noexcept { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); lsn_t lsn= log_sys.get_lsn(); log_sys.latch.wr_unlock(); return lsn; @@ -525,7 +522,7 @@ static void log_resize_acquire() noexcept group_commit_lock::ACQUIRED); } - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); } /** Release the latches that protect the log. */ @@ -951,7 +948,7 @@ void log_t::persist(lsn_t lsn) noexcept ATTRIBUTE_NOINLINE static void log_write_persist(lsn_t lsn) noexcept { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); log_sys.persist(lsn); log_sys.latch.wr_unlock(); } @@ -1113,7 +1110,6 @@ lsn_t log_t::write_buf() noexcept } } - set_check_for_checkpoint(false); return lsn; } @@ -1188,7 +1184,7 @@ repeat: group_commit_lock::ACQUIRED) { ut_ad(!recv_no_log_write || srv_operation != SRV_OPERATION_NORMAL); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); pending_write_lsn= write_lock.release(log_sys.writer()); } @@ -1252,7 +1248,7 @@ void log_t::clear_mmap() noexcept #ifdef HAVE_PMEM if (!is_opened()) { - ut_d(latch.wr_lock(SRW_LOCK_CALL)); + ut_d(latch.wr_lock()); ut_ad(!resize_in_progress()); ut_ad(get_lsn() == get_flushed_lsn(std::memory_order_relaxed)); ut_d(latch.wr_unlock()); @@ -1265,22 +1261,31 @@ void log_t::clear_mmap() noexcept ut_ad(write_lsn == get_lsn()); ut_ad(write_lsn == get_flushed_lsn(std::memory_order_relaxed)); - if (buf) /* this may be invoked while creating a new database */ { - alignas(16) byte log_block[4096]; - const size_t bs{write_size}; + if (buf) /* this may be invoked while creating a new database */ { - const size_t bf= - size_t(write_lsn - base_lsn.load(std::memory_order_relaxed)); - memcpy_aligned<16>(log_block, buf + (bf & ~(bs - 1)), bs); + alignas(16) byte log_block[log_t::WRITE_SIZE_MAX]; + const size_t bs{write_size}; + { + ut_ad(write_lsn >= first_lsn); + uint64_t bf{write_lsn - first_lsn}; + if (bf > capacity()) + bf%= capacity(); + bf+= START_OFFSET; + const size_t bs_1{bs - 1}; + write_lsn_offset= bf & bs_1; + base_lsn.store(write_lsn - write_lsn_offset, + std::memory_order_relaxed); + memcpy_aligned<16>(log_block, buf + (bf & ~uint64_t{bs_1}), bs); + } + + close_file(false); + log_mmap= false; + ut_a(attach(log, file_size)); + ut_ad(!is_mmap()); + + memcpy_aligned<16>(buf, log_block, bs); } - - close_file(false); - log_mmap= false; - ut_a(attach(log, file_size)); - ut_ad(!is_mmap()); - - memcpy_aligned<16>(buf, log_block, bs); } log_resize_release(); } @@ -1301,46 +1306,53 @@ ATTRIBUTE_COLD void log_write_and_flush() noexcept } } -/****************************************************************//** -Tries to establish a big enough margin of free space in the log, such -that a new log entry can be catenated without an immediate need for a -checkpoint. NOTE: this function may only be called if the calling thread -owns no synchronization objects! */ -ATTRIBUTE_COLD static void log_checkpoint_margin() noexcept +ATTRIBUTE_COLD void log_t::checkpoint_margin() noexcept { - while (log_sys.check_for_checkpoint()) + ut_ad(this == &log_sys); + ut_ad(!recv_no_log_write); + + thd_wait_begin(nullptr, THD_WAIT_DISKIO); + tpool::tpool_wait_begin(); + + while (check_for_checkpoint()) { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + latch.wr_lock(); ut_ad(!recv_no_log_write); - if (!log_sys.check_for_checkpoint()) + if (!check_for_checkpoint()) { -func_exit: - log_sys.latch.wr_unlock(); - return; + func_exit: + latch.wr_unlock(); + break; } - const lsn_t lsn= log_sys.get_lsn(); - const lsn_t max_age= log_sys.max_checkpoint_age; - const lsn_t age= lsn_t(lsn - log_sys.last_checkpoint_lsn); + const lsn_t last{last_checkpoint_lsn}, max_age{max_checkpoint_age}; + lsn_t lsn{get_lsn()}; - if (age <= max_age) + ut_ad(last >= first_lsn); { + if (lsn - last <= max_age) + { #ifndef DBUG_OFF - skip_checkpoint: + skip_checkpoint: #endif - log_sys.set_check_for_checkpoint(false); - goto func_exit; + set_check_for_checkpoint(false); + goto func_exit; + } + DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", goto skip_checkpoint;); + lsn-= max_age; } - DBUG_EXECUTE_IF("ib_log_checkpoint_avoid_hard", goto skip_checkpoint;); - log_sys.latch.wr_unlock(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); /* We must wait to prevent the tail of the log overwriting the head. */ - buf_flush_wait_flushed(lsn - max_age); - /* Sleep to avoid a thundering herd */ - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + buf_flush_wait(lsn, false); + latch.wr_unlock(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); } + + tpool::tpool_wait_end(); + thd_wait_end(nullptr); } /** Wait for a log checkpoint if needed. @@ -1352,7 +1364,7 @@ void log_free_check() noexcept if (log_sys.check_for_checkpoint()) { ut_ad(!recv_no_log_write); - log_checkpoint_margin(); + log_sys.checkpoint_margin(); } } @@ -1362,13 +1374,14 @@ extern void buf_mem_pressure_shutdown() noexcept; inline void buf_mem_pressure_shutdown() noexcept {} #endif -/** Make a checkpoint at the latest lsn on shutdown. */ -ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown() noexcept +/** Make a checkpoint at the latest lsn on shutdown. +@return the shutdown LSN */ +ATTRIBUTE_COLD lsn_t logs_empty_and_mark_files_at_shutdown() noexcept { - lsn_t lsn; ulint count = 0; - ib::info() << "Starting shutdown..."; + sql_print_information("InnoDB: Starting shutdown..."); + ut_ad(buf_pool.is_initialised() || !srv_was_started); /* Wait until the master task and all other operations are idle: our algorithm only works if the server is idle at shutdown */ @@ -1387,17 +1400,17 @@ ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown() noexcept } srv_monitor_timer.reset(); -loop: + constexpr ulint COUNT_INTERVAL{600}; + if (false) { + loop: + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + count++; + } + ut_ad(lock_sys.is_initialised() || !srv_was_started); ut_ad(log_sys.is_initialised() || !srv_was_started); ut_ad(fil_system.is_initialised() || !srv_was_started); -#define COUNT_INTERVAL 600U -#define CHECK_INTERVAL 100000U - std::this_thread::sleep_for(std::chrono::microseconds(CHECK_INTERVAL)); - - count++; - /* Check that there are no longer transactions, except for PREPARED ones. We need this wait even for the 'very fast' shutdown, because the InnoDB layer may have committed or @@ -1409,12 +1422,12 @@ loop: if (srv_print_verbose_log && count > COUNT_INTERVAL) { service_manager_extend_timeout( - COUNT_INTERVAL * CHECK_INTERVAL/1000000 * 2, - "Waiting for %lu active transactions to finish", - (ulong) total_trx); - ib::info() << "Waiting for " << total_trx << " active" - << " transactions to finish"; - + unsigned(COUNT_INTERVAL / 5), + "Waiting for %zu active transactions to finish", + total_trx); + sql_print_information("InnoDB: Waiting for %zu active" + " transactions to finish", + total_trx); count = 0; } @@ -1428,11 +1441,11 @@ loop: ut_ad(!srv_read_only_mode); wait_suspend_loop: service_manager_extend_timeout( - COUNT_INTERVAL * CHECK_INTERVAL/1000000 * 2, + unsigned(COUNT_INTERVAL / 5), "Waiting for %s to exit", thread_name); if (srv_print_verbose_log && count > COUNT_INTERVAL) { - ib::info() << "Waiting for " << thread_name - << " to exit"; + sql_print_information("InnoDB: Waiting for %s to exit", + thread_name); count = 0; } goto loop; @@ -1447,67 +1460,36 @@ wait_suspend_loop: goto wait_suspend_loop; } - if (buf_page_cleaner_is_active) { - thread_name = "page cleaner thread"; - pthread_cond_signal(&buf_pool.do_flush_list); - goto wait_suspend_loop; - } + if (buf_pool.is_initialised()) { + if (srv_fast_shutdown != 2 && !srv_read_only_mode + && srv_was_started) { + log_make_checkpoint(); + } - buf_load_dump_end(); - rollback_all_recovered_task.wait(); + buf_load_dump_end(); + rollback_all_recovered_task.wait(); - if (!buf_pool.is_initialised()) { - ut_ad(!srv_was_started); - } else { - buf_flush_buffer_pool(); - } + mysql_mutex_lock(&buf_pool.flush_list_mutex); + srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; + while (buf_page_cleaner_is_active) { + pthread_cond_signal(&buf_pool.do_flush_list); + my_cond_wait(&buf_pool.done_flush_list, + &buf_pool.flush_list_mutex.m_mutex); + } + mysql_mutex_unlock(&buf_pool.flush_list_mutex); - if (srv_fast_shutdown == 2 || !srv_was_started) { - if (!srv_read_only_mode && srv_was_started) { + if (srv_fast_shutdown == 2 && !srv_read_only_mode) { sql_print_information( "InnoDB: Executing innodb_fast_shutdown=2." " Next startup will execute crash recovery!"); - - /* In this fastest shutdown we do not flush the - buffer pool: - - it is essentially a 'crash' of the InnoDB server. - Make sure that the log is all flushed to disk, so - that we can recover all committed transactions in - a crash recovery. */ log_buffer_flush_to_disk(); } - - srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; - return; } - if (!srv_read_only_mode) { - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "ensuring dirty buffer pool are written to log"); - log_make_checkpoint(); - - const auto sizeof_cp = log_sys.is_encrypted() - ? SIZE_OF_FILE_CHECKPOINT + 8 - : SIZE_OF_FILE_CHECKPOINT; - - log_sys.latch.wr_lock(SRW_LOCK_CALL); - - lsn = log_sys.get_lsn(); - - const bool lsn_changed = lsn != log_sys.last_checkpoint_lsn - && lsn != log_sys.last_checkpoint_lsn + sizeof_cp; - ut_ad(lsn >= log_sys.last_checkpoint_lsn); - - log_sys.latch.wr_unlock(); - - if (lsn_changed) { - goto loop; - } - } else { - lsn = recv_sys.lsn; + const lsn_t lsn{log_get_lsn()}; + if (srv_fast_shutdown == 2 || !srv_was_started) { + return lsn; } - srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; /* Make some checks that the server really is quiet */ @@ -1515,24 +1497,18 @@ wait_suspend_loop: service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, "Free innodb buffer pool"); + /* There could be pending writes to the temporary tablespace. */ + os_aio_wait_until_no_pending_writes(false); + /* Some recently triggered read-ahead may be pending. */ + os_aio_wait_until_no_pending_reads(false); + ut_d(mysql_mutex_lock(&buf_pool.mutex)); ut_d(buf_pool.assert_all_freed()); - - ut_a(lsn == log_get_lsn() - || srv_force_recovery == SRV_FORCE_NO_LOG_REDO); - - if (UNIV_UNLIKELY(lsn < recv_sys.lsn)) { - sql_print_error("InnoDB: Shutdown LSN=" LSN_PF - " is less than start LSN=" LSN_PF, - lsn, recv_sys.lsn); - } - - srv_shutdown_lsn = lsn; - - /* Make some checks that the server really is quiet */ - ut_ad(!srv_any_background_activity()); - - ut_a(lsn == log_get_lsn() + ut_d(mysql_mutex_unlock(&buf_pool.mutex)); + ut_a(lsn == log_sys.last_checkpoint_lsn + SIZE_OF_FILE_CHECKPOINT + + 8 * log_sys.is_encrypted() || srv_force_recovery == SRV_FORCE_NO_LOG_REDO); + ut_a(lsn >= recv_sys.lsn); + return lsn; } /******************************************************//** @@ -1542,7 +1518,7 @@ log_print( /*======*/ FILE* file) /*!< in: file where to print */ { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const lsn_t lsn= log_sys.get_lsn(); mysql_mutex_lock(&buf_pool.flush_list_mutex); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e3792b04957..c7dcb530504 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -800,7 +800,7 @@ retry: log_sys.latch.wr_unlock(); fil_space_t *space= fil_system.sys_space; buf_block_t *free_block= buf_LRU_get_free_block(have_no_mutex); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); mysql_mutex_lock(&recv_sys.mutex); for (auto d= defers.begin(); d != defers.end(); ) @@ -1599,7 +1599,7 @@ ATTRIBUTE_COLD static dberr_t recv_log_recover_pre_10_2() if (o >= 0x80c && (o & ~511) + 512 < log_size) { max_no= checkpoint_no; - log_sys.next_checkpoint_lsn= mach_read_from_8(buf + CHECKPOINT_LSN); + log_sys.last_checkpoint_lsn= mach_read_from_8(buf + CHECKPOINT_LSN); source_offset= o; } } @@ -1608,7 +1608,7 @@ ATTRIBUTE_COLD static dberr_t recv_log_recover_pre_10_2() ? "InnoDB: Upgrade after a crash is not supported." : "mariadb-backup --prepare is not possible."; - if (!log_sys.next_checkpoint_lsn) + if (!log_sys.last_checkpoint_lsn) { sql_print_error("%s" " This redo log was created before MariaDB 10.2.2," @@ -1631,7 +1631,7 @@ ATTRIBUTE_COLD static dberr_t recv_log_recover_pre_10_2() if (log_block_calc_checksum_format_0(buf) != mach_read_from_4(my_assume_aligned<4>(buf + 508)) && - !log_crypt_101_read_block(buf, log_sys.next_checkpoint_lsn)) + !log_crypt_101_read_block(buf, log_sys.last_checkpoint_lsn)) { sql_print_error("%s%s, and it appears corrupted.", uag, pre_10_2); return DB_CORRUPTION; @@ -1678,7 +1678,7 @@ static dberr_t recv_log_recover_10_5(lsn_t lsn_offset) } if (log_sys.is_encrypted() && - !log_decrypt(buf, log_sys.next_checkpoint_lsn & ~511, 512)) + !log_decrypt(buf, log_sys.last_checkpoint_lsn & ~511, 512)) return DB_ERROR; /* On a clean shutdown, the redo log will be logically empty @@ -1753,14 +1753,14 @@ dberr_t recv_sys_t::find_checkpoint() { if (wrong_size) return DB_CORRUPTION; - lsn= log_sys.next_checkpoint_lsn; + lsn= log_sys.last_checkpoint_lsn; log_sys.format= log_t::FORMAT_3_23; goto upgrade; } } else ut_ad(srv_operation == SRV_OPERATION_BACKUP); - log_sys.next_checkpoint_lsn= 0; + log_sys.last_checkpoint_lsn= 0; lsn= 0; buf= my_assume_aligned<4096>(log_sys.buf); if (!log_sys.is_mmap()) @@ -1778,9 +1778,8 @@ dberr_t recv_sys_t::find_checkpoint() upgrade: memset_aligned<4096>(const_cast(field_ref_zero), 0, 4096); /* Mark the redo log for upgrading. */ - log_sys.last_checkpoint_lsn= log_sys.next_checkpoint_lsn; - log_sys.set_recovered_lsn(log_sys.next_checkpoint_lsn); - lsn= file_checkpoint= log_sys.next_checkpoint_lsn; + lsn= file_checkpoint= log_sys.last_checkpoint_lsn; + log_sys.set_recovered_lsn(lsn); if (UNIV_LIKELY(lsn != 0)) scanned_lsn= lsn; log_sys.next_checkpoint_no= 0; @@ -1848,14 +1847,14 @@ dberr_t recv_sys_t::find_checkpoint() continue; } - if (checkpoint_lsn >= log_sys.next_checkpoint_lsn) + if (checkpoint_lsn >= log_sys.last_checkpoint_lsn) { - log_sys.next_checkpoint_lsn= checkpoint_lsn; + log_sys.last_checkpoint_lsn= checkpoint_lsn; log_sys.next_checkpoint_no= field == log_t::CHECKPOINT_1; lsn= end_lsn; } } - if (!log_sys.next_checkpoint_lsn) + if (!log_sys.last_checkpoint_lsn) goto got_no_checkpoint; if (!memcmp(creator, "Backup ", 7)) srv_start_after_restore= true; @@ -1908,14 +1907,14 @@ dberr_t recv_sys_t::find_checkpoint() if (checkpoint_no >= max_no && o >= 0x80c && (o & ~511) + 512 < log_size) { max_no= checkpoint_no; - log_sys.next_checkpoint_lsn= checkpoint_lsn; + log_sys.last_checkpoint_lsn= checkpoint_lsn; log_sys.next_checkpoint_no= field == 512; lsn_offset= mach_read_from_8(b + 16); } } } - if (!log_sys.next_checkpoint_lsn) + if (!log_sys.last_checkpoint_lsn) { got_no_checkpoint: sql_print_error("InnoDB: No valid checkpoint was found;" @@ -2078,7 +2077,7 @@ ATTRIBUTE_COLD void recv_sys_t::wait_for_pool(size_t pages) const size_t available= UT_LIST_GET_LEN(buf_pool.free); mysql_mutex_unlock(&buf_pool.mutex); if (available < pages) - buf_flush_sync_batch(lsn); + buf_flush_sync_batch(lsn, false); } /** Register a redo log snippet for a page. @@ -2476,7 +2475,7 @@ recv_sys_t::parse_mtr_result recv_sys_t::parse(source l, bool if_exists) (srv_operation == SRV_OPERATION_BACKUP || srv_operation == SRV_OPERATION_BACKUP_NO_DEFER)); mysql_mutex_assert_owner(&mutex); - ut_ad(log_sys.next_checkpoint_lsn); + ut_ad(log_sys.last_checkpoint_lsn); ut_ad(log_sys.is_recoverable()); ut_ad(log_sys.format == format); @@ -2748,17 +2747,11 @@ log_parse_file(const page_id_t id, bool if_exists, { if (UNIV_UNLIKELY(srv_print_verbose_log == 2)) fprintf(stderr, "FILE_CHECKPOINT(" LSN_PF ") %s at " LSN_PF "\n", - c, c != log_sys.next_checkpoint_lsn + c, c != log_sys.last_checkpoint_lsn ? "ignored" : recv_sys.file_checkpoint ? "reread" : "read", recv_sys.lsn); - DBUG_PRINT("ib_log", - ("FILE_CHECKPOINT(" LSN_PF ") %s at " LSN_PF, - c, c != log_sys.next_checkpoint_lsn - ? "ignored" : recv_sys.file_checkpoint ? "reread" : "read", - recv_sys.lsn)); - - if (c == log_sys.next_checkpoint_lsn) + if (c == log_sys.last_checkpoint_lsn) { /* There can be multiple FILE_CHECKPOINT for the same LSN. */ if (!recv_sys.file_checkpoint) @@ -3845,7 +3838,7 @@ bool recv_sys_t::apply_batch(uint32_t space_id, fil_space_t *&space, unlock_relock: mysql_mutex_unlock(&mutex); relock: - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); relock_last: mysql_mutex_lock(&mutex); get_last: @@ -4067,6 +4060,30 @@ static void log_sort_flush_list() noexcept mysql_mutex_unlock(&buf_pool.flush_list_mutex); } +/** Invalidate all pages in the buffer pool. +All pages must be replaceable (not modified, latched, or io-fixed). */ +ATTRIBUTE_COLD static void buf_pool_invalidate() noexcept +{ + mysql_mutex_lock(&buf_pool.mutex); + ut_ad(!os_aio_pending_reads()); + /* os_aio_pending_writes() may hold here if some write_io_callback() + did not release the slot yet. However, buf_flush_sync_batch() waited + for the page write itself to complete, which we will check below. */ + ut_d(buf_pool.assert_all_freed()); + + while (UT_LIST_GET_LEN(buf_pool.LRU)) + buf_LRU_scan_and_free_block(); + + ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); + + buf_pool.freed_page_clock= 0; + buf_pool.LRU_old= nullptr; + buf_pool.LRU_old_len= 0; + buf_pool.stat.init(); + buf_refresh_io_stats(); + mysql_mutex_unlock(&buf_pool.mutex); +} + /** Apply buffered log to persistent data pages. @param last_batch whether it is possible to write more redo log */ void recv_sys_t::apply(bool last_batch) @@ -4158,7 +4175,7 @@ void recv_sys_t::apply(bool last_batch) recv_sys.mutex. */ free_block= buf_LRU_get_free_block(have_no_mutex); if (!last_batch) - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); mysql_mutex_lock(&mutex); pages_it= pages.begin(); } @@ -4207,13 +4224,13 @@ void recv_sys_t::apply(bool last_batch) if (!last_batch) { - buf_flush_sync_batch(lsn); + buf_flush_sync_batch(lsn, false); buf_pool_invalidate(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); } else if (srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_EXPORT) - buf_flush_sync_batch(lsn); + buf_flush_sync_batch(lsn, false); else /* Instead of flushing, last_batch sorts the buf_pool.flush_list in ascending order of buf_page_t::oldest_modification. */ @@ -4307,7 +4324,7 @@ static bool recv_scan_log(bool last_phase, const recv_sys_t::parser *parser) if (UNIV_UNLIKELY(!recv_needed_recovery)) { ut_ad(!last_phase); - ut_ad(recv_sys.lsn >= log_sys.next_checkpoint_lsn); + ut_ad(recv_sys.lsn >= log_sys.last_checkpoint_lsn); if (!store) { @@ -4335,7 +4352,7 @@ static bool recv_scan_log(bool last_phase, const recv_sys_t::parser *parser) { recv_sys.set_corrupt_log(); sql_print_error("InnoDB: Missing FILE_CHECKPOINT(" LSN_PF - ") at " LSN_PF, log_sys.next_checkpoint_lsn, + ") at " LSN_PF, log_sys.last_checkpoint_lsn.load(), recv_sys.lsn); } mysql_mutex_unlock(&recv_sys.mutex); @@ -4360,7 +4377,7 @@ static bool recv_scan_log(bool last_phase, const recv_sys_t::parser *parser) } sql_print_information("InnoDB: Starting crash recovery from" " checkpoint LSN=" LSN_PF, - log_sys.next_checkpoint_lsn); + log_sys.last_checkpoint_lsn.load()); } } } @@ -4739,30 +4756,6 @@ done: return err; } -dberr_t recv_recovery_read_checkpoint() -{ - ut_ad(srv_operation <= SRV_OPERATION_EXPORT_RESTORED || - srv_operation == SRV_OPERATION_RESTORE || - srv_operation == SRV_OPERATION_RESTORE_EXPORT); - ut_ad(!recv_sys.recovery_on); - ut_d(mysql_mutex_lock(&buf_pool.mutex)); - ut_ad(UT_LIST_GET_LEN(buf_pool.LRU) == 0); - ut_ad(UT_LIST_GET_LEN(buf_pool.unzip_LRU) == 0); - ut_d(mysql_mutex_unlock(&buf_pool.mutex)); - - if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) - { - sql_print_information("InnoDB: innodb_force_recovery=6" - " skips redo log apply"); - return DB_SUCCESS; - } - - log_sys.latch.wr_lock(SRW_LOCK_CALL); - dberr_t err= recv_sys.find_checkpoint(); - log_sys.latch.wr_unlock(); - return err; -} - inline void log_t::set_recovered() noexcept { ut_ad(get_flushed_lsn() == get_lsn()); @@ -4783,13 +4776,14 @@ inline void log_t::set_recovered() noexcept inline bool recv_sys_t::validate_checkpoint() const noexcept { - if (lsn >= file_checkpoint && lsn >= log_sys.next_checkpoint_lsn) + const lsn_t last_checkpoint_lsn{log_sys.last_checkpoint_lsn}; + if (lsn >= file_checkpoint && lsn >= last_checkpoint_lsn) return false; sql_print_error("InnoDB: The log was only scanned up to " LSN_PF ", while the current LSN at the " "time of the latest checkpoint " LSN_PF " was " LSN_PF "!", - lsn, log_sys.next_checkpoint_lsn, file_checkpoint); + lsn, last_checkpoint_lsn, file_checkpoint); return true; } @@ -4836,7 +4830,7 @@ dberr_t recv_recovery_from_checkpoint_start() recv_sys.recovery_on = true; - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); log_sys.set_capacity(); /* Start reading the log from the checkpoint lsn. */ @@ -4853,8 +4847,7 @@ func_exit: if (log_sys.is_recoverable()) { const bool rewind = recv_sys.lsn - != log_sys.next_checkpoint_lsn; - log_sys.last_checkpoint_lsn = log_sys.next_checkpoint_lsn; + != log_sys.last_checkpoint_lsn; parser[false] = get_parse_mmap(); parser[true] = get_parse_mmap(); recv_scan_log(false, parser); @@ -4876,7 +4869,7 @@ read_only_recovery: ut_ad(recv_sys.file_checkpoint); ut_ad(log_sys.get_flushed_lsn() >= recv_sys.scanned_lsn); if (rewind) { - recv_sys.lsn = log_sys.next_checkpoint_lsn; + recv_sys.lsn = log_sys.last_checkpoint_lsn; recv_sys.offset = 0; recv_sys.len = 0; } @@ -4938,7 +4931,7 @@ read_only_recovery: mysql_mutex_lock(&recv_sys.mutex); ut_ad(log_sys.get_flushed_lsn() >= recv_sys.lsn); recv_sys.clear(); - recv_sys.lsn = log_sys.next_checkpoint_lsn; + recv_sys.lsn = log_sys.last_checkpoint_lsn; mysql_mutex_unlock(&recv_sys.mutex); } @@ -5161,7 +5154,7 @@ const byte *recv_dblwr_t::find_page(const page_id_t page_id, lsn_t max_lsn, continue; } - if (lsn > max_lsn || lsn < log_sys.next_checkpoint_lsn || + if (lsn > max_lsn || lsn < log_sys.last_checkpoint_lsn || !validate_page(page_id, max_lsn, space, page, tmp_buf)) { /* Mark processed for subsequent iterations in buf_dblwr_t::recover() */ diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index e279cd77134..68467d9cefa 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -260,7 +260,7 @@ static void insert_imported(buf_block_t *block) { if (block->page.oldest_modification() <= 1) { - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); /* For unlogged mtrs (MTR_LOG_NO_REDO), we use the current system LSN. The mtr that generated the LSN is either already committed or in mtr_t::commit. Shared latch and relaxed atomics should be fine here as it is guaranteed @@ -562,7 +562,7 @@ void mtr_t::commit_shrink(fil_space_t &space, uint32_t size) log_write_and_flush_prepare(); m_latch_ex= true; - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const lsn_t start_lsn= do_write().first; ut_d(m_log.erase()); @@ -680,7 +680,7 @@ bool mtr_t::commit_file(fil_space_t &space, const char *name) const size_t size{crypt ? 8 + encrypt() : crc32c()}; log_write_and_flush_prepare(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); finish_write(size); if (!name && space.max_lsn) @@ -886,7 +886,7 @@ ATTRIBUTE_COLD void log_t::append_prepare_wait(bool late, bool ex) noexcept if (!late) { /* Wait for all threads to back off. */ - latch.wr_lock(SRW_LOCK_CALL); + latch.wr_lock(); goto got_ex; } @@ -938,13 +938,13 @@ ATTRIBUTE_COLD void log_t::append_prepare_wait(bool late, bool ex) noexcept log_write_up_to(lsn, false); if (ex) { - latch.wr_lock(SRW_LOCK_CALL); + latch.wr_lock(); return; } } done: - latch.rd_lock(SRW_LOCK_CALL); + latch.rd_lock(); } /** Reserve space in the log buffer for appending data. @@ -1021,7 +1021,7 @@ static lsn_t log_close(lsn_t lsn) noexcept limit (lsn - log_sys.max_checkpoint_age) in order to minimize the synchronous wait time. */ if (furious) - log_sys.set_check_for_checkpoint(); + log_sys.set_check_for_checkpoint(true); return ((lsn - max_age) & ~lsn_t{1}) | lsn_t{furious}; } @@ -1098,7 +1098,7 @@ std::pair mtr_t::do_write() noexcept const size_t len{log_sys.is_encrypted() ? 8 + encrypt() : crc32c()}; if (!m_latch_ex) - log_sys.latch.rd_lock(SRW_LOCK_CALL); + log_sys.latch.rd_lock(); if (UNIV_UNLIKELY(m_user_space && !m_user_space->max_lsn && !srv_is_undo_tablespace((m_user_space->id)))) @@ -1107,7 +1107,7 @@ std::pair mtr_t::do_write() noexcept { m_latch_ex= true; log_sys.latch.rd_unlock(); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); if (UNIV_UNLIKELY(m_user_space->max_lsn != 0)) goto func_exit; } diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index d50cf18e2b8..6494c5e21b9 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -1631,8 +1631,7 @@ bool os_file_set_size(const char *name, os_file_t file, os_offset_t size, /* Write buffer full of zeros */ memset(buf, 0, buf_size); - while (current_size < size - && srv_shutdown_state <= SRV_SHUTDOWN_INITIATED) { + while (current_size < size) { ulint n_bytes; if (size - current_size < (os_offset_t) buf_size) { diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 87d02da38e5..af72252f5f7 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2776,7 +2776,13 @@ err_exit: if (!index->table->n_rec_locks && !index->table->versioned() && !index->table->is_temporary() - && !index->table->has_spatial_index()) { + && !index->table->has_spatial_index() + /* Prevent ALTER IGNORE from using bulk insert + optimization. since it requires to write undo log + for each row operation that's incompatible with + bulk operations */ + && index->table->skip_alter_undo != + dict_table_t::IGNORE_UNDO) { ut_ad(!index->table->skip_alter_undo); trx->bulk_insert = TRX_DML_BULK; @@ -3316,7 +3322,7 @@ row_ins_clust_index_entry( skip the undo log and record lock checking for insertion operation. */ - if (index->table->skip_alter_undo) { + if (index->table->skip_alter_undo == dict_table_t::NO_UNDO) { flags |= BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG; } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index b36731a02c2..6c83de220f7 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -120,7 +120,7 @@ public: ut_ad(mtr_started == scan_mtr->is_active()); DBUG_EXECUTE_IF("row_merge_instrument_log_check_flush", - log_sys.set_check_for_checkpoint();); + log_sys.set_check_for_checkpoint(true);); for (idx_tuple_vec::iterator it = m_dtuple_vec.begin(); it != m_dtuple_vec.end(); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 0bbc90cd0f6..0a749743f16 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -74,7 +74,7 @@ static void row_mysql_delay_if_needed() noexcept if (UNIV_UNLIKELY(delay != 0)) { /* Adjust for purge_coordinator_state::refresh() */ - log_sys.latch.rd_lock(SRW_LOCK_CALL); + log_sys.latch.rd_lock(); const lsn_t last= log_sys.last_checkpoint_lsn, max_age= log_sys.max_checkpoint_age; const lsn_t lsn= log_sys.get_flushed_lsn(); @@ -690,8 +690,8 @@ handle_new_error: bulk buffer in row_mysql_handle_errors(). For ALTER TABLE ALGORITHM=COPY & CREATE TABLE...SELECT, the bulk insert transaction will be rolled back inside - ha_innobase::extra(HA_EXTRA_ABORT_ALTER_COPY) */ - trx->bulk_insert &= TRX_DDL_BULK; + ha_innobase::extra(HA_EXTRA_ABORT_COPY) */ + trx->clear_dml_bulk(); trx->last_stmt_start = 0; break; case DB_LOCK_WAIT: @@ -1276,12 +1276,7 @@ row_insert_for_mysql( node->vers_update_end(prebuilt, ins_mode == ROW_INS_HISTORICAL); } - /* Because we now allow multiple INSERT into the same - initially empty table in bulk insert mode, on error we must - roll back to the start of the transaction. For correctness, it - would suffice to roll back to the start of the first insert - into this empty table, but we will keep it simple and efficient. */ - const undo_no_t savept{trx->bulk_insert ? 0 : trx->undo_no}; + undo_no_t savept = trx->undo_no; thr = que_fork_get_first_thr(prebuilt->ins_graph); @@ -1308,6 +1303,24 @@ error_exit: /* FIXME: What's this ? */ thr->lock_state = QUE_THR_LOCK_ROW; + /* Because we now allow multiple INSERT into the same + initially empty table in bulk insert mode, on error we must + roll back to the start of the transaction. For correctness, it + would suffice to roll back to the start of the first insert + into this empty table, but we will keep it simple and efficient. + + In ALTER IGNORE...ALGORITHM=COPY (IGNORE_UNDO mode), + trx_undo_report_row_operation() rewrites the insert undo log to + retain only the latest record, resetting trx->undo_no to 0 + before each new insert. We must use savept=0 so that partial + rollback targets the single surviving undo record. */ + static_assert(TRX_DML_BULK & 2, ""); + static_assert(TRX_DDL_BULK & 2, ""); + static_assert(dict_table_t::IGNORE_UNDO == 2, ""); + if ((trx->bulk_insert | table->skip_alter_undo) & 2) { + savept = 0; + } + was_lock_wait = row_mysql_handle_errors( &err, trx, thr, &savept); diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index e3bb2b412ca..c2e6f7a0b78 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -435,7 +435,7 @@ close_table: node->table = NULL; return false; } else { - ut_ad(!node->table->skip_alter_undo); + ut_ad(node->table->skip_alter_undo != dict_table_t::NO_UNDO); clust_index = dict_table_get_first_index(node->table); if (clust_index != NULL) { diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 2de3e473b21..57fa45a3df3 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -171,7 +171,7 @@ row_undo_search_clust_to_pcur( rec_offs* offsets = offsets_; rec_offs_init(offsets_); - ut_ad(!node->table->skip_alter_undo); + ut_ad(node->table->skip_alter_undo != dict_table_t::NO_UNDO); mtr_start(&mtr); diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index cc3ed576fa5..ebdf9f31c01 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -1498,7 +1498,7 @@ srv_mon_process_existing_counter( break; case MONITOR_LSN_CHECKPOINT_AGE: - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); value = static_cast(log_sys.get_lsn() - log_sys.last_checkpoint_lsn); log_sys.latch.wr_unlock(); diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index f9fffde59bb..e304f0c8613 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -949,7 +949,7 @@ srv_export_innodb_status(void) mysql_mutex_unlock(&srv_innodb_monitor_mutex); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); export_vars.innodb_lsn_current = log_sys.get_lsn(); export_vars.innodb_lsn_flushed = log_sys.get_flushed_lsn(); export_vars.innodb_lsn_last_checkpoint = log_sys.last_checkpoint_lsn; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 33d68eef613..cee2b782561 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -91,9 +91,6 @@ Created 2/16/1996 Heikki Tuuri #include "zlib.h" #include "log.h" -/** Log sequence number at shutdown */ -lsn_t srv_shutdown_lsn; - /** TRUE if a raw partition is in use */ ibool srv_start_raw_disk_in_use; @@ -171,7 +168,9 @@ static void delete_log_files() @return DB_SUCCESS or error code */ static dberr_t create_log_file(bool create_new_db, lsn_t lsn) { + ut_ad(log_sys.latch_have_wr()); ut_ad(!srv_read_only_mode); + ut_ad(!buf_pool.get_oldest_modification(0)); /* We will retain ib_logfile0 until we have written a new logically empty log as ib_logfile101 and atomically renamed it to @@ -179,9 +178,6 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn) delete_log_files(); ut_ad(!os_aio_pending_reads()); - ut_d(mysql_mutex_lock(&buf_pool.flush_list_mutex)); - ut_ad(!buf_pool.get_oldest_modification(0)); - ut_d(mysql_mutex_unlock(&buf_pool.flush_list_mutex)); /* os_aio_pending_writes() may hold here if some write_io_callback() did not release the slot yet. However, the page write itself must have completed, because the @@ -190,7 +186,6 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn) assumption does not hold. */ ut_d(os_aio_wait_until_no_pending_writes(false)); - log_sys.latch.wr_lock(SRW_LOCK_CALL); log_sys.set_capacity(); std::string logfile0{get_log_file_path("ib_logfile101")}; @@ -206,6 +201,7 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn) int(logfile0.size()), logfile0.data()); err_exit: log_sys.latch.wr_unlock(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); return DB_ERROR; } @@ -223,14 +219,6 @@ close_and_exit: goto close_and_exit; } - mysql_mutex_lock(&recv_sys.mutex); - const bool all_opened = fil_system.sys_space->open(create_new_db); - mysql_mutex_unlock(&recv_sys.mutex); - - if (!all_opened) { - goto err_exit; - } - /* Create a log checkpoint. */ if (log_sys.is_encrypted() && !log_crypt_init()) { goto err_exit; @@ -255,9 +243,9 @@ close_and_exit: buf_page_t::read_complete(). */ recv_sys.recovery_on = false; log_sys.latch.wr_unlock(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); log_make_checkpoint(); - log_buffer_flush_to_disk(); return DB_SUCCESS; } @@ -414,23 +402,6 @@ inline dberr_t trx_sys_t::reset_page(mtr_t *mtr) return DB_SUCCESS; } -/** Delete the old undo tablespaces present in the undo log directory */ -static dberr_t srv_undo_delete_old_tablespaces() -{ - /* Delete the old undo tablespaces*/ - for (uint32_t i= 0; i < srv_undo_tablespaces_open; ++i) - fil_close_tablespace(srv_undo_space_id_start + i); - - DBUG_EXECUTE_IF("after_deleting_old_undo_abort", return DB_ERROR;); - - /* Do checkpoint to get rid of old undo log tablespaces redo logs */ - log_make_checkpoint(); - - DBUG_EXECUTE_IF("after_deleting_old_undo_success", return DB_ERROR;); - - return DB_SUCCESS; -} - /** Recreate the undo log tablespaces */ ATTRIBUTE_COLD static dberr_t srv_undo_tablespaces_reinit() { @@ -533,17 +504,35 @@ ATTRIBUTE_COLD static dberr_t srv_undo_tablespaces_reinit() DBUG_EXECUTE_IF("after_rseg_reset_abort", log_write_up_to(mtr.commit_lsn(), true); - dict_hdr->page.unfix(); - return DB_ERROR;); + err= DB_ERROR; goto unfix_exit;); + + log_make_checkpoint(); sql_print_information( "InnoDB: Reinitializing innodb_undo_tablespaces= %u from %u", srv_undo_tablespaces, srv_undo_tablespaces_open); /* Delete the old undo tablespaces */ - err= srv_undo_delete_old_tablespaces(); - if (err) + for (uint32_t i= 0; i < srv_undo_tablespaces_open; ++i) + fil_close_tablespace(srv_undo_space_id_start + i); + + DBUG_EXECUTE_IF("after_deleting_old_undo_abort", + err= DB_ERROR; goto unfix_exit;); + + /* Do checkpoint to get rid of old undo log tablespaces redo logs */ + log_make_checkpoint(); + + DBUG_EXECUTE_IF("after_deleting_old_undo_success", + err= DB_ERROR; goto unfix_exit;); + + if (srv_undo_tablespaces == 0) { + srv_undo_space_id_start= 0; + srv_undo_tablespaces_open= 0; + srv_undo_tablespaces_active= 0; +#ifndef DBUG_OFF + unfix_exit: +#endif dict_hdr->page.unfix(); return err; } @@ -553,27 +542,16 @@ ATTRIBUTE_COLD static dberr_t srv_undo_tablespaces_reinit() dict_hdr->page.lock.x_lock(); mtr.memo_push(dict_hdr, MTR_MEMO_PAGE_X_FIX); - if (srv_undo_tablespaces == 0) - { - srv_undo_space_id_start= 0; - srv_undo_tablespaces_open= 0; - goto func_exit; - } - srv_undo_space_id_start= latest_space_id; if (fil_assign_new_space_id(&srv_undo_space_id_start)) - mtr.write<4>(*dict_hdr, DICT_HDR + DICT_HDR_MAX_SPACE_ID - + dict_hdr->page.frame, srv_undo_space_id_start); + mtr.write<4>(*dict_hdr, DICT_HDR + DICT_HDR_MAX_SPACE_ID + + dict_hdr->page.frame, srv_undo_space_id_start); /* Re-create the new undo tablespaces */ err= srv_undo_tablespaces_init(true, &mtr); func_exit: mtr.commit(); - DBUG_EXECUTE_IF("after_reinit_undo_abort", - log_write_up_to(mtr.commit_lsn(), true); - err= DB_ERROR;); - if (err == DB_SUCCESS) { /* Usually, recovery must work no matter when @@ -584,10 +562,8 @@ func_exit: were written in mtr and also srv_undo_tablespaces_init() initializes the undo tablespace start id based on page0 content before reading the redo log */ - log_make_checkpoint(); - - DBUG_EXECUTE_IF("after_reinit_undo_success", err= DB_ERROR;); srv_undo_tablespaces_active= srv_undo_tablespaces; + log_make_checkpoint(); } return err; } @@ -1089,38 +1065,28 @@ srv_init_abort_low( /** Prepare to delete the redo log file. Flush the dirty pages from all the buffer pools. Flush the redo log buffer to the redo log file. -@return lsn upto which data pages have been flushed. */ -ATTRIBUTE_COLD static lsn_t srv_prepare_to_delete_redo_log_file() noexcept +@return lsn upto which data pages have been flushed and log_sys.latch acquired +@retval 0 in case of error; log_sys.latch will not be acquired */ +static ATTRIBUTE_COLD lsn_t srv_prepare_to_delete_redo_log_file() noexcept { DBUG_ENTER("srv_prepare_to_delete_redo_log_file"); + mysql_mutex_lock(&recv_sys.mutex); ut_ad(recv_sys.recovery_on); + recv_sys.apply(true); + mysql_mutex_unlock(&recv_sys.mutex); /* Clean the buffer pool. */ - buf_flush_sync(); + buf_flush_sync_batch(0, false); - DBUG_EXECUTE_IF("innodb_log_abort_1", DBUG_RETURN(0);); + DBUG_EXECUTE_IF("innodb_log_abort_1", recv_sys.recovery_on= false; + DBUG_RETURN(0);); DBUG_PRINT("ib_log", ("After innodb_log_abort_1")); - log_sys.latch.wr_lock(SRW_LOCK_CALL); + log_sys.latch.wr_lock(); const bool latest_format{log_sys.is_latest()}; lsn_t flushed_lsn{log_sys.get_flushed_lsn(std::memory_order_relaxed)}; - if (latest_format && !(log_sys.file_size & 4095) && - flushed_lsn != log_sys.next_checkpoint_lsn + - (log_sys.is_encrypted() - ? SIZE_OF_FILE_CHECKPOINT + 8 - : SIZE_OF_FILE_CHECKPOINT)) - { -#ifdef HAVE_PMEM - if (!log_sys.is_opened()) - log_sys.buf_size= unsigned(std::min(log_sys.capacity(), - log_sys.buf_size_max)); -#endif - fil_names_clear(flushed_lsn); - flushed_lsn= log_sys.get_lsn(); - } - { const char *msg; if (!latest_format) @@ -1152,48 +1118,31 @@ same_size: } } - log_sys.latch.wr_unlock(); - - if (latest_format) - log_write_up_to(flushed_lsn, false); - - ut_ad(flushed_lsn == log_get_lsn()); - ut_ad(!os_aio_pending_reads()); - ut_d(mysql_mutex_lock(&buf_pool.flush_list_mutex)); - ut_ad(!buf_pool.get_oldest_modification(0)); - ut_d(mysql_mutex_unlock(&buf_pool.flush_list_mutex)); - ut_d(os_aio_wait_until_no_pending_writes(false)); - DBUG_RETURN(flushed_lsn); } /** Upgrade the redo log to the latest format, or change its size or encryption, before starting to write any log records. */ -ATTRIBUTE_COLD static dberr_t srv_log_rebuild() +ATTRIBUTE_COLD static dberr_t srv_log_rebuild() noexcept { /* Prepare to delete the old redo log file */ const lsn_t lsn{srv_prepare_to_delete_redo_log_file()}; - - DBUG_EXECUTE_IF("innodb_log_abort_1", return DB_ERROR;); + if (!lsn) + return DB_ERROR; + mysql_mutex_lock(&buf_pool.flush_list_mutex); + ut_ad(!buf_pool.get_oldest_modification(0)); /* Prohibit redo log writes from any other threads until creating a log checkpoint at the end of create_log_file(). */ ut_d(recv_no_log_write= true); ut_ad(!os_aio_pending_reads()); - ut_d(mysql_mutex_lock(&buf_pool.flush_list_mutex)); - ut_ad(!buf_pool.get_oldest_modification(0)); - ut_d(mysql_mutex_unlock(&buf_pool.flush_list_mutex)); - /* os_aio_pending_writes() may hold here if some write_io_callback() - did not release the slot yet. However, the page write itself must - have completed, because the buf_pool.flush_list is empty. In debug - builds, we wait for this to happen, hoping to get a hung process if - this assumption does not hold. */ - ut_d(os_aio_wait_until_no_pending_writes(false)); + DBUG_EXECUTE_IF("innodb_log_abort_5", + recv_sys.recovery_on= false; recv_no_log_write= false; + log_sys.latch.wr_unlock(); + mysql_mutex_unlock(&buf_pool.flush_list_mutex); + return DB_ERROR;); /* Close the redo log file, so that we can replace it */ log_sys.close_file(); - - DBUG_EXECUTE_IF("innodb_log_abort_5", return DB_ERROR;); - dberr_t err= create_log_file(false, lsn); if (err == DB_SUCCESS && log_sys.resize_rename()) @@ -1203,7 +1152,7 @@ ATTRIBUTE_COLD static dberr_t srv_log_rebuild() } /** Rebuild the redo log if needed. */ -static dberr_t srv_log_rebuild_if_needed() +static dberr_t srv_log_rebuild_if_needed() noexcept { if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) /* Completely ignore the redo log. */ @@ -1244,7 +1193,7 @@ ATTRIBUTE_COLD static dberr_t ibuf_log_rebuild_if_needed() inline lsn_t log_t::init_lsn() noexcept { - latch.wr_lock(SRW_LOCK_CALL); + latch.wr_lock(); ut_ad(!write_lsn_offset); write_lsn_offset= 0; const lsn_t lsn{base_lsn.load(std::memory_order_relaxed)}; @@ -1454,9 +1403,21 @@ dberr_t srv_start(bool create_new_db) } recv_sys.debug_free(); } else { - err = recv_recovery_read_checkpoint(); - if (err != DB_SUCCESS) { - return srv_init_abort(err); + ut_ad(srv_operation <= SRV_OPERATION_EXPORT_RESTORED + || srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT); + ut_ad(!recv_sys.recovery_on); + + if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) { + sql_print_information("InnoDB: innodb_force_recovery=6" + " skips redo log apply"); + } else { + log_sys.latch.wr_lock(); + err = recv_sys.find_checkpoint(); + log_sys.latch.wr_unlock(); + if (err != DB_SUCCESS) { + return srv_init_abort(err); + } } } @@ -1489,6 +1450,8 @@ dberr_t srv_start(bool create_new_db) if (create_new_db) { lsn_t flushed_lsn = log_sys.init_lsn(); + log_sys.latch.wr_lock(); + mysql_mutex_lock(&buf_pool.flush_list_mutex); err = create_log_file(true, flushed_lsn); @@ -1587,8 +1550,6 @@ dberr_t srv_start(bool create_new_db) return(srv_init_abort(err)); } - buf_flush_sync(); - ut_ad(!srv_log_file_created); ut_d(srv_log_file_created= true); @@ -2086,28 +2047,7 @@ void innodb_shutdown() { innodb_preshutdown(); ut_ad(!srv_undo_sources); - switch (srv_operation) { - case SRV_OPERATION_BACKUP: - case SRV_OPERATION_RESTORE_DELTA: - case SRV_OPERATION_BACKUP_NO_DEFER: - break; - case SRV_OPERATION_RESTORE: - case SRV_OPERATION_RESTORE_EXPORT: - mysql_mutex_lock(&buf_pool.flush_list_mutex); - srv_shutdown_state = SRV_SHUTDOWN_CLEANUP; - while (buf_page_cleaner_is_active) { - pthread_cond_signal(&buf_pool.do_flush_list); - my_cond_wait(&buf_pool.done_flush_list, - &buf_pool.flush_list_mutex.m_mutex); - } - mysql_mutex_unlock(&buf_pool.flush_list_mutex); - break; - case SRV_OPERATION_NORMAL: - case SRV_OPERATION_EXPORT_RESTORED: - /* Shut down the persistent files. */ - logs_empty_and_mark_files_at_shutdown(); - } - + const lsn_t lsn{logs_empty_and_mark_files_at_shutdown()}; innodb_binlog_close(true); os_aio_free(); fil_space_t::close_all(); @@ -2186,14 +2126,15 @@ void innodb_shutdown() } srv_tmp_space.shutdown(); - if (srv_stats.pages_page_compression_error) - ib::warn() << "Page compression errors: " - << srv_stats.pages_page_compression_error; + if (const size_t pce = srv_stats.pages_page_compression_error) { + sql_print_warning("InnoDB: Page compression errors: %zu", pce); + } - if (srv_was_started && srv_print_verbose_log) { - ib::info() << "Shutdown completed; log sequence number " - << srv_shutdown_lsn - << "; transaction id " << trx_sys.get_max_trx_id(); + if (lsn && srv_was_started && srv_print_verbose_log) { + sql_print_information("Shutdown completed;" + " log sequence number " LSN_PF ";" + " transaction id " TRX_ID_FMT, + lsn, trx_sys.get_max_trx_id()); } srv_thread_pool_end(); srv_started_redo = false; diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc index cd5f92f85f2..5a419373ffe 100644 --- a/storage/innobase/sync/srw_lock.cc +++ b/storage/innobase/sync/srw_lock.cc @@ -761,4 +761,126 @@ bool srw_lock_debug::have_any() const noexcept { return have_wr() || have_rd(); } + +# if defined LOG_LATCH_DEBUG && defined UNIV_PFS_RWLOCK +void srw_lock_debug_simple::init() noexcept +{ + ssux_lock_impl::init(); + readers_lock.init(); + ut_ad(!readers.load(std::memory_order_relaxed)); + ut_ad(!have_any()); +} + +void srw_lock_debug_simple::destroy() noexcept +{ + ut_ad(!writer); + if (auto r= readers.load(std::memory_order_relaxed)) + { + readers.store(0, std::memory_order_relaxed); + ut_ad(r->empty()); + delete r; + } + readers_lock.destroy(); + ssux_lock_impl::destroy(); +} + +bool srw_lock_debug_simple::wr_lock_try() noexcept +{ + ut_ad(!have_any()); + if (!ssux_lock_impl::wr_lock_try()) + return false; + ut_ad(!writer); + writer.store(pthread_self(), std::memory_order_relaxed); + return true; +} + +void srw_lock_debug_simple::wr_lock() noexcept +{ + ut_ad(!have_any()); + ssux_lock_impl::wr_lock(); + ut_ad(!writer); + writer.store(pthread_self(), std::memory_order_relaxed); +} + +void srw_lock_debug_simple::wr_unlock() noexcept +{ + ut_ad(have_wr()); + writer.store(0, std::memory_order_relaxed); + ssux_lock_impl::wr_unlock(); +} + +void srw_lock_debug_simple::readers_register() noexcept +{ + readers_lock.wr_lock(); + auto r= readers.load(std::memory_order_relaxed); + if (!r) + { + r= new std::unordered_multiset(); + readers.store(r, std::memory_order_relaxed); + } + r->emplace(pthread_self()); + readers_lock.wr_unlock(); +} + +bool srw_lock_debug_simple::rd_lock_try() noexcept +{ + ut_ad(!have_any()); + if (!ssux_lock_impl::rd_lock_try()) + return false; + readers_register(); + return true; +} + +void srw_lock_debug_simple::rd_lock() noexcept +{ + ut_ad(!have_any()); + ssux_lock_impl::rd_lock(); + readers_register(); +} + +void srw_lock_debug_simple::rd_unlock() noexcept +{ + const pthread_t self= pthread_self(); + ut_ad(writer != self); + readers_lock.wr_lock(); + auto r= readers.load(std::memory_order_relaxed); + ut_ad(r); + auto i= r->find(self); + ut_ad(i != r->end()); + r->erase(i); + readers_lock.wr_unlock(); + + ssux_lock_impl::rd_unlock(); +} + +bool srw_lock_debug_simple::have_rd() const noexcept +{ + if (auto r= readers.load(std::memory_order_relaxed)) + { + readers_lock.wr_lock(); + bool found= r->find(pthread_self()) != r->end(); + readers_lock.wr_unlock(); +# ifndef SUX_LOCK_GENERIC + ut_ad(!found || is_locked()); +# endif + return found; + } + return false; +} + +bool srw_lock_debug_simple::have_wr() const noexcept +{ + if (writer != pthread_self()) + return false; +# ifndef SUX_LOCK_GENERIC + ut_ad(is_write_locked()); +# endif + return true; +} + +bool srw_lock_debug_simple::have_any() const noexcept +{ + return have_wr() || have_rd(); +} +# endif #endif diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index fbde1ae465d..cfe42f77e4c 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1795,6 +1795,30 @@ static bool trx_has_lock_x(const trx_t &trx, dict_table_t& table) return false; } +/** For ALTER TABLE...IGNORE ALGORITHM=COPY, rewind the undo log +to maintain only the latest insert undo record. This allows easy +rollback of the last inserted row on duplicate key errors. +@param mtr mini-transaction +@param undo_block undo log page +@param table table being altered +@param trx transaction +@param undo insert undo log +@return mod_tables entry after inserting the table */ +static ATTRIBUTE_COLD ATTRIBUTE_NOINLINE +std::pair +trx_undo_rewrite_ignore(mtr_t *mtr, buf_block_t *undo_block, + dict_table_t *table, trx_t *trx, trx_undo_t *undo) +{ + mtr->write<2>(*undo_block, undo_block->page.frame + TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_FREE, undo->old_offset); + ut_ad(trx->undo_no == 1); + undo->top_offset= undo->old_offset; + undo->top_undo_no= 0; + trx->undo_no= 0; + trx->mod_tables.clear(); + return trx->mod_tables.emplace(table, 0); +} + /***********************************************************************//** Writes information to an undo log about an insert, update, or a delete marking of a clustered index record. This information is used in a rollback of the @@ -1900,9 +1924,19 @@ trx_undo_report_row_operation( ut_ad(!trx->read_only); ut_ad(trx->id); pundo = &trx->rsegs.m_redo.undo; + const bool clear_ignore = *pundo && trx->undo_no + && (*pundo)->old_offset <= (*pundo)->top_offset + && index->table->skip_alter_undo + == dict_table_t::IGNORE_UNDO; + rseg = trx->rsegs.m_redo.rseg; undo_block = trx_undo_assign_low(&mtr, &err, rseg, pundo); + if (clear_ignore) { + ut_ad(!rec); + m = trx_undo_rewrite_ignore(&mtr, undo_block, + index->table, trx, *pundo); + } } trx_undo_t* undo = *pundo; @@ -1989,6 +2023,8 @@ err_exit: /* Success */ undo->top_page_no = undo_block->page.id().page_no(); mtr.commit(); + + undo->old_offset = offset; undo->top_offset = offset; undo->top_undo_no = trx->undo_no++; undo->guess_block = undo_block; diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index 1cce439f6e1..be1815ab602 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1173,6 +1173,8 @@ trx_undo_mem_create( undo->rseg = rseg; + undo->top_offset = 0; + undo->old_offset = 0; undo->hdr_page_no = page_no; undo->hdr_offset = offset; undo->last_page_no = page_no; diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 98ddd70c3d6..bb9920fc662 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -5791,7 +5791,7 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record, /* Store length of all not empty char, varchar and blob fields */ log_parts->str= field_lengths - 2; log_parts->length= info->cur_row.field_lengths_length+2; - int2store(log_parts->str, info->cur_row.field_lengths_length); + int2store((void *)log_parts->str, info->cur_row.field_lengths_length); row_length+= log_parts->length; log_parts++; } diff --git a/storage/maria/ma_rt_index.c b/storage/maria/ma_rt_index.c index a84ea65f749..ad56e33639b 100644 --- a/storage/maria/ma_rt_index.c +++ b/storage/maria/ma_rt_index.c @@ -931,7 +931,6 @@ static int maria_rtree_delete_req(MARIA_HA *info, const MARIA_KEY *key, my_off_t page_pos, uint *page_size, stPageList *ReinsertList, int level) { - ulong i; uint nod_flag; int res; my_bool buff_alloced; @@ -959,9 +958,9 @@ static int maria_rtree_delete_req(MARIA_HA *info, const MARIA_KEY *key, k= rt_PAGE_FIRST_KEY(share, page_buf, nod_flag); last= rt_PAGE_END(&page); - for (i= 0; + for (; k < last; - k= rt_PAGE_NEXT_KEY(share, k, key->data_length, nod_flag), i++) + k= rt_PAGE_NEXT_KEY(share, k, key->data_length, nod_flag)) { if (nod_flag) { diff --git a/storage/maria/ma_sp_key.c b/storage/maria/ma_sp_key.c index 45d05c6f996..c85e8bae9de 100644 --- a/storage/maria/ma_sp_key.c +++ b/storage/maria/ma_sp_key.c @@ -47,7 +47,6 @@ MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr, uint dlen; uchar *dptr; double mbr[SPDIMS * 2]; - uint i; DBUG_ENTER("_ma_sp_make_key"); keyseg = &keyinfo->seg[-1]; @@ -64,7 +63,7 @@ MARIA_KEY *_ma_sp_make_key(MARIA_HA *info, MARIA_KEY *ret_key, uint keynr, sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */ - for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++) + for (keyseg = keyinfo->seg; keyseg->type; keyseg++) { uint length = keyseg->length, start= keyseg->start; double val; diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 49ad7ade115..9a609118aaf 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -548,14 +548,17 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation) case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN: inspected = "HA_EXTRA_STARTING_ORDERED_INDEX_SCAN"; break; - case HA_EXTRA_BEGIN_ALTER_COPY: - inspected = "HA_EXTRA_BEGIN_ALTER_COPY"; + case HA_EXTRA_BEGIN_COPY: + inspected = "HA_EXTRA_BEGIN_COPY"; break; - case HA_EXTRA_END_ALTER_COPY: - inspected = "HA_EXTRA_END_ALTER_COPY"; + case HA_EXTRA_END_COPY: + inspected = "HA_EXTRA_END_COPY"; break; - case HA_EXTRA_ABORT_ALTER_COPY: - inspected = "HA_EXTRA_ABORT_ALTER_COPY"; + case HA_EXTRA_ABORT_COPY: + inspected = "HA_EXTRA_ABORT_COPY"; + break; + case HA_EXTRA_BEGIN_ALTER_IGNORE_COPY: + inspected = "HA_EXTRA_BEGIN_ALTER_IGNORE_COPY"; break; #ifdef MRN_HAVE_HA_EXTRA_EXPORT case HA_EXTRA_EXPORT: @@ -582,19 +585,19 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation) inspected = "HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW"; break; #endif -#ifdef MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY - case HA_EXTRA_BEGIN_ALTER_COPY: - inspected = "HA_EXTRA_BEGIN_ALTER_COPY"; +#ifdef MRN_HAVE_HA_EXTRA_BEGIN_COPY + case HA_EXTRA_BEGIN_COPY: + inspected = "HA_EXTRA_BEGIN_COPY"; break; #endif -#ifdef MRN_HAVE_HA_EXTRA_END_ALTER_COPY - case HA_EXTRA_END_ALTER_COPY: - inspected = "HA_EXTRA_END_ALTER_COPY"; +#ifdef MRN_HAVE_HA_EXTRA_END_COPY + case HA_EXTRA_END_COPY: + inspected = "HA_EXTRA_END_COPY"; break; #endif -#ifdef MRN_HAVE_HA_EXTRA_ABORT_ALTER_COPY - case HA_EXTRA_ABORT_ALTER_COPY: - inspected = "HA_EXTRA_ABORT_ALTER_COPY"; +#ifdef MRN_HAVE_HA_EXTRA_ABORT_COPY + case HA_EXTRA_ABORT_COPY: + inspected = "HA_EXTRA_ABORT_COPY"; break; #endif #ifdef MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING @@ -772,6 +775,27 @@ static MYSQL_SYSVAR_ENUM(log_level, mrn_log_level, static_cast(mrn_log_level), &mrn_log_level_typelib); +static int mrn_log_file_check(THD *thd, struct st_mysql_sys_var *var, + void *save, struct st_mysql_value *value) +{ + MRN_DBUG_ENTER_FUNCTION(); + + char buf[STRING_BUFFER_USUAL_SIZE]; + int len = sizeof(buf); + const char* new_value = value->val_str(value, buf, &len); + + if (!new_value || len == 0) { + my_printf_error(ER_MRN_INVALID_NULL_VALUE_NUM, + ER_MRN_INVALID_NULL_VALUE_STR, + MYF(0), + "mroonga_log_file"); + DBUG_RETURN(1); + } + + *((const char**)save) = thd->strmake(new_value, len); + + DBUG_RETURN(0); +} static void mrn_log_file_update(THD *thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save) { @@ -844,7 +868,7 @@ static void mrn_log_file_update(THD *thd, struct st_mysql_sys_var *var, static MYSQL_SYSVAR_STR(log_file, mrn_log_file_path, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, "log file for " MRN_PLUGIN_NAME_STRING, - NULL, + mrn_log_file_check, mrn_log_file_update, MRN_LOG_FILE_PATH); @@ -934,6 +958,12 @@ static void mrn_default_tokenizer_update(THD *thd, struct st_mysql_sys_var *var, char **old_value_ptr = (char **)var_ptr; grn_ctx *ctx = &mrn_ctx; + if(!new_value) { + new_value = "off"; +#ifndef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR + new_value = mrn_my_strdup(new_value, MYF(MY_WME)); +#endif + } mrn_change_encoding(ctx, system_charset_info); if (strcmp(*old_value_ptr, new_value) == 0) { GRN_LOG(ctx, GRN_LOG_NOTICE, diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_disable.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_disable.result new file mode 100644 index 00000000000..45f1c7adddf --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_disable.result @@ -0,0 +1,5 @@ +SET GLOBAL mroonga_default_tokenizer = NULL; +SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer'; +Variable_name Value +mroonga_default_tokenizer off +SET GLOBAL mroonga_default_tokenizer = DEFAULT; diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_reject_null.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_reject_null.result new file mode 100644 index 00000000000..c44462e7ac9 --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_reject_null.result @@ -0,0 +1,7 @@ +SET GLOBAL mroonga_log_file = NULL; +ERROR HY000: NULL value can't be used for mroonga_log_file +SET GLOBAL mroonga_log_file = ''; +ERROR HY000: NULL value can't be used for mroonga_log_file +SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file'; +Variable_name Value +mroonga_log_file groonga.log diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_disable.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_disable.test new file mode 100644 index 00000000000..63df372f3fa --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_disable.test @@ -0,0 +1,25 @@ +# -*- mode: sql; sql-product: mysql -*- +# +# Copyright (C) 2026 hadeer +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +--source include/not_embedded.inc +--source ../../include/mroonga/have_mroonga.inc + +SET GLOBAL mroonga_default_tokenizer = NULL; +SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer'; +SET GLOBAL mroonga_default_tokenizer = DEFAULT; + +--source ../../include/mroonga/have_mroonga_deinit.inc diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_reject_null.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_reject_null.test new file mode 100644 index 00000000000..f6c53f1e682 --- /dev/null +++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_reject_null.test @@ -0,0 +1,30 @@ +# -*- mode: sql; sql-product: mysql -*- +# +# Copyright (C) 2026 hadeer +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +--source ../../include/mroonga/have_mroonga.inc +--source include/not_embedded.inc + +--error 16505 +SET GLOBAL mroonga_log_file = NULL; + +--error 16505 +SET GLOBAL mroonga_log_file = ''; + +SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file'; + +--source ../../include/mroonga/have_mroonga_deinit.inc diff --git a/storage/mroonga/vendor/groonga/lib/db.c b/storage/mroonga/vendor/groonga/lib/db.c index 9fe636b1a4e..d194334a03e 100644 --- a/storage/mroonga/vendor/groonga/lib/db.c +++ b/storage/mroonga/vendor/groonga/lib/db.c @@ -1988,7 +1988,7 @@ exit: if (ii_cursor) { grn_ii_cursor_close(ctx, ii_cursor); } - grn_obj_unlink(ctx, &source_ids); + GRN_OBJ_FIN(ctx, &source_ids); { int i, n_sources; n_sources = GRN_BULK_VSIZE(&sources) / sizeof(grn_obj *); @@ -1996,7 +1996,7 @@ exit: grn_obj *source = GRN_PTR_VALUE_AT(&sources, i); grn_obj_unlink(ctx, source); } - grn_obj_unlink(ctx, &sources); + GRN_OBJ_FIN(ctx, &sources); } } diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index 444e34fe136..f51a1f6953a 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -275,7 +275,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) mysql_mutex_unlock(&share->intern_lock); mysql_mutex_unlock(&THR_LOCK_myisam); break; - case HA_EXTRA_END_ALTER_COPY: + case HA_EXTRA_END_COPY: case HA_EXTRA_FLUSH: mysql_mutex_lock(&share->intern_lock); if (!share->temporary) diff --git a/storage/myisam/rt_index.c b/storage/myisam/rt_index.c index 3bc9a41b81d..a1e8af5df15 100644 --- a/storage/myisam/rt_index.c +++ b/storage/myisam/rt_index.c @@ -764,7 +764,6 @@ static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, { uchar *k; uchar *last; - ulong i; uint nod_flag; uchar *page_buf; int res; @@ -784,7 +783,7 @@ static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); - for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i) + for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) { if (nod_flag) { diff --git a/storage/myisam/sp_key.c b/storage/myisam/sp_key.c index 5d4e96bff28..877a1eab661 100644 --- a/storage/myisam/sp_key.c +++ b/storage/myisam/sp_key.c @@ -39,7 +39,6 @@ uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, uint dlen; uchar *dptr; double mbr[SPDIMS * 2]; - uint i; keyseg = &keyinfo->seg[-1]; pos = (uchar*)record + keyseg->start; @@ -53,7 +52,7 @@ uint sp_make_key(register MI_INFO *info, uint keynr, uchar *key, } sp_mbr_from_wkb(dptr + 4, dlen - 4, SPDIMS, mbr); /* SRID */ - for (i = 0, keyseg = keyinfo->seg; keyseg->type; keyseg++, i++) + for (keyseg = keyinfo->seg; keyseg->type; keyseg++) { uint length = keyseg->length, start= keyseg->start; double val; diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_38732.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_38732.result new file mode 100644 index 00000000000..39de1a7b246 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_38732.result @@ -0,0 +1,22 @@ +for master_1 +for child2 +for child3 +set spider_same_server_link= 1; +CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); +CREATE TABLE t (f INT); +INSERT INTO t VALUES (1),(2); +SET @a = 4; +SET @a = NULL; +CREATE TABLE t_spider LIKE t; +ALTER TABLE t_spider ENGINE=SPIDER COMMENT = 'wrapper "mysql", srv "srv", table "t"'; +Warnings: +Warning 138 Spider table params in COMMENT or CONNECTION strings have been deprecated and will be removed in a future release. Please use table options instead. +DELETE FROM t_spider WHERE f > 0 or f < @a; +SELECT * FROM t_spider; +f +drop table t, t_spider; +drop server srv; +for master_1 +for child2 +for child3 diff --git a/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result index eb262b1c209..dcd18c344d1 100644 --- a/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result +++ b/storage/spider/mysql-test/spider/bugfix/r/xa_cmd.result @@ -36,6 +36,14 @@ INSERT INTO tbl_a (pkey) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); XA END 'test'; XA PREPARE 'test'; XA COMMIT 'test'; +# MDEV-35426 Stack smashing in spider_db_mbase::xa_end (opt), ASAN: stack- +# buffer-overflow in Binary_string::q_append, and Assertion +# `str.alloced_length() >= str.length() + data_len' failed in +# spider_string::q_append on SELECT. +XA START 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; +INSERT INTO tbl_a (pkey) VALUES (10); +XA END 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; +XA ROLLBACK 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; # MDEV-37829 XA COMMIT ONE PHASE fails with "This xid does not # exist" if a trigger references a SPIDER table # @@ -105,6 +113,7 @@ connection child2_1; SELECT argument FROM mysql.general_log WHERE command_type != 'Execute' AND argument LIKE '%insert %'; argument insert into `auto_test_remote`.`tbl_a`(`pkey`)values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9) +insert into `auto_test_remote`.`tbl_a`(`pkey`)values(10) insert into `auto_test_remote`.`tbl_a`(`pkey`)values(100) insert high_priority into `auto_test_remote`.`tbl_a`(`pkey`)values(101) insert high_priority into `auto_test_remote`.`tbl_a`(`pkey`)values(102) diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_38732.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_38732.test new file mode 100644 index 00000000000..0371a49d7b5 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_38732.test @@ -0,0 +1,26 @@ +--disable_query_log +--disable_result_log +--source ../../t/test_init.inc +--enable_result_log +--enable_query_log + +set spider_same_server_link= 1; +evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql +OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); + +CREATE TABLE t (f INT); +INSERT INTO t VALUES (1),(2); +SET @a = 4; +SET @a = NULL; +CREATE TABLE t_spider LIKE t; +ALTER TABLE t_spider ENGINE=SPIDER COMMENT = 'wrapper "mysql", srv "srv", table "t"'; +DELETE FROM t_spider WHERE f > 0 or f < @a; +SELECT * FROM t_spider; + +drop table t, t_spider; +drop server srv; +--disable_query_log +--disable_result_log +--source ../../t/test_deinit.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test index db34518f01b..7304ee2f410 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test +++ b/storage/spider/mysql-test/spider/bugfix/t/xa_cmd.test @@ -53,6 +53,16 @@ XA END 'test'; XA PREPARE 'test'; XA COMMIT 'test'; +--echo # MDEV-35426 Stack smashing in spider_db_mbase::xa_end (opt), ASAN: stack- +--echo # buffer-overflow in Binary_string::q_append, and Assertion +--echo # `str.alloced_length() >= str.length() + data_len' failed in +--echo # spider_string::q_append on SELECT. + +XA START 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; +INSERT INTO tbl_a (pkey) VALUES (10); +XA END 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; +XA ROLLBACK 'xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc1','xaaaaaaaaaaaaaaabbbbbbbbbbbbbbbccc2',1234567890; + --echo # MDEV-37829 XA COMMIT ONE PHASE fails with "This xid does not --echo # exist" if a trigger references a SPIDER table --echo # diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index 667f97e0dd0..adca8dc0ea1 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -48,8 +48,6 @@ extern SPIDER_DBTON spider_dbton[SPIDER_DBTON_SIZE]; #define SPIDER_SQL_COALESCE_STR "coalesce(" #define SPIDER_SQL_COALESCE_LEN (sizeof(SPIDER_SQL_COALESCE_STR) - 1) -#define SPIDER_SQL_HEX_STR "0x" -#define SPIDER_SQL_HEX_LEN (sizeof(SPIDER_SQL_HEX_STR) - 1) #define SPIDER_SQL_SET_NAMES_STR "set names " #define SPIDER_SQL_SET_NAMES_LEN sizeof(SPIDER_SQL_SET_NAMES_STR) - 1 @@ -1127,7 +1125,7 @@ void spider_db_append_xid_str( spider_string *tmp_str, XID *xid ) { - char format_id[sizeof(long) + 3]; + char format_id[3*sizeof(long) + 3]; uint format_id_length; DBUG_ENTER("spider_db_append_xid_str"); @@ -7562,8 +7560,10 @@ int spider_db_open_item_int( if (!(tmp_str2 = item->val_str(tmp_str.get_str()))) { - error_num = HA_ERR_OUT_OF_MEM; - goto end; + if (str->reserve(SPIDER_SQL_NULL_LEN)) + error_num = HA_ERR_OUT_OF_MEM; + str->q_append(SPIDER_SQL_NULL_STR, SPIDER_SQL_NULL_LEN); + DBUG_RETURN(error_num); } tmp_str.mem_calc(); diff --git a/storage/spider/spd_db_conn.h b/storage/spider/spd_db_conn.h index 1de59f43858..e81a5ee4a72 100644 --- a/storage/spider/spd_db_conn.h +++ b/storage/spider/spd_db_conn.h @@ -24,6 +24,8 @@ #define SPIDER_DB_KEY_NAME_LEN (sizeof(SPIDER_DB_KEY_NAME_STR) - 1) #define SPIDER_DB_SEQUENCE_NAME_STR "" #define SPIDER_DB_SEQUENCE_NAME_LEN (sizeof(SPIDER_DB_SEQUENCE_NAME_STR) - 1) +#define SPIDER_SQL_HEX_STR "0x" +#define SPIDER_SQL_HEX_LEN (sizeof(SPIDER_SQL_HEX_STR) - 1) #define SPIDER_DB_TABLE_LOCK_READ_LOCAL 0 #define SPIDER_DB_TABLE_LOCK_READ 1 diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index b920a313784..e0a0b93e90b 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -2580,7 +2580,9 @@ int spider_db_mbase::xa_end( XID *xid, int *need_mon ) { - char sql_buf[SPIDER_SQL_XA_END_LEN + XIDDATASIZE + sizeof(long) + 9]; + char sql_buf[SPIDER_SQL_XA_END_LEN + XIDDATASIZE*2 + + SPIDER_SQL_HEX_LEN*2 + SPIDER_SQL_COMMA_LEN*2 + + sizeof(long)*3 + 7]; spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin); DBUG_ENTER("spider_db_mbase::xa_end"); DBUG_PRINT("info",("spider this=%p", this)); @@ -2597,7 +2599,9 @@ int spider_db_mbase::xa_prepare( XID *xid, int *need_mon ) { - char sql_buf[SPIDER_SQL_XA_PREPARE_LEN + XIDDATASIZE + sizeof(long) + 9]; + char sql_buf[SPIDER_SQL_XA_PREPARE_LEN + XIDDATASIZE*2 + + SPIDER_SQL_HEX_LEN*2 + SPIDER_SQL_COMMA_LEN*2 + + sizeof(long)*3 + 7]; spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin); DBUG_ENTER("spider_db_mbase::xa_prepare"); DBUG_PRINT("info",("spider this=%p", this)); @@ -2614,7 +2618,9 @@ int spider_db_mbase::xa_commit( XID *xid, int *need_mon ) { - char sql_buf[SPIDER_SQL_XA_COMMIT_LEN + XIDDATASIZE + sizeof(long) + 9]; + char sql_buf[SPIDER_SQL_XA_COMMIT_LEN + XIDDATASIZE*2 + + SPIDER_SQL_HEX_LEN*2 + SPIDER_SQL_COMMA_LEN*2 + + sizeof(long)*3 + 7]; spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin); DBUG_ENTER("spider_db_mbase::xa_commit"); DBUG_PRINT("info",("spider this=%p", this)); @@ -2631,7 +2637,9 @@ int spider_db_mbase::xa_rollback( XID *xid, int *need_mon ) { - char sql_buf[SPIDER_SQL_XA_ROLLBACK_LEN + XIDDATASIZE + sizeof(long) + 9]; + char sql_buf[SPIDER_SQL_XA_ROLLBACK_LEN + XIDDATASIZE*2 + + SPIDER_SQL_HEX_LEN*2 + SPIDER_SQL_COMMA_LEN*2 + + sizeof(long)*3 + 7]; spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin); DBUG_ENTER("spider_db_mbase::xa_rollback"); DBUG_PRINT("info",("spider this=%p", this)); @@ -4722,7 +4730,8 @@ int spider_db_mbase_util::append_xa_start( DBUG_ENTER("spider_db_mbase_util::append_xa_start"); DBUG_PRINT("info",("spider this=%p", this)); if (str->reserve(SPIDER_SQL_SEMICOLON_LEN + - SPIDER_SQL_XA_START_LEN + XIDDATASIZE + sizeof(long) + 9)) + SPIDER_SQL_XA_START_LEN + XIDDATASIZE*2 + SPIDER_SQL_HEX_LEN*2 + + SPIDER_SQL_COMMA_LEN*2 + sizeof(long)*3 + 7)) DBUG_RETURN(HA_ERR_OUT_OF_MEM); if (str->length()) { diff --git a/strings/ctype-uca1400.c b/strings/ctype-uca1400.c index 986ec669730..7ff3d1f1c7e 100644 --- a/strings/ctype-uca1400.c +++ b/strings/ctype-uca1400.c @@ -306,7 +306,8 @@ my_bool my_uca1400_collation_definition_add(MY_CHARSET_LOADER *loader, uint id) param.nopad_flags); const MY_UCA1400_COLLATION_DEFINITION *def= &my_uca1400_collation_definitions[param.tailoring_id]; - + if (!src) + return FALSE; coll_name= my_uca1400_collation_build_name(coll_name_buffer, sizeof(coll_name_buffer), &src->cs_name, diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index 16c905cdd62..ecfb7c1ca9a 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -159,7 +159,7 @@ LimitNOFILE=32768 # Library substitutions. previously [mysqld_safe] malloc-lib with explicit paths # (in LD_LIBRARY_PATH) and library name (in LD_PRELOAD). -# Environment="LD_LIBRARY_PATH=/path1 /path2" "LD_PRELOAD= +# Environment="LD_LIBRARY_PATH=/path1 /path2" "LD_PRELOAD=" # Flush caches. previously [mysqld_safe] flush-caches=1 # ExecStartPre=sync diff --git a/support-files/mariadb@.service.in b/support-files/mariadb@.service.in index 04713d61308..cea04c71307 100644 --- a/support-files/mariadb@.service.in +++ b/support-files/mariadb@.service.in @@ -283,7 +283,7 @@ LimitNOFILE=32768 # Library substitutions. previously [mysqld_safe] malloc-lib with explicit paths # (in LD_LIBRARY_PATH) and library name (in LD_PRELOAD). -# Environment="LD_LIBRARY_PATH=/path1 /path2" "LD_PRELOAD= +# Environment="LD_LIBRARY_PATH=/path1 /path2" "LD_PRELOAD=" # Flush caches. previously [mysqld_safe] flush-caches=1 # ExecStartPre=sync diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9d59e120f3e..d55a3ba1520 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -22814,6 +22814,112 @@ insert into t1 values(\ rc= mysql_query(mysql, "DROP TABLE t1"); myquery(rc); } + +static void run_tests_36678( + const char *test, + const char *table_stmt, + const char *insert_stmt, + const char *view_stmt, + const char *proc_stmt, + const char *call_stmt) +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind; + int rc; + + myheader(test); + + if ((table_stmt && table_stmt[0] != '\0' && + (rc= mysql_query_or_error(mysql, table_stmt)))) + DIE("Table creation failed"); + + if ((insert_stmt && insert_stmt[0] != '\0' && + (rc= mysql_query_or_error(mysql, insert_stmt)))) + DIE("Table insertion failed"); + + if ((rc= mysql_query_or_error(mysql, view_stmt)) || + (rc= mysql_query_or_error(mysql, proc_stmt))) + DIE("View/Proc creation failed"); + + stmt= mysql_stmt_init(mysql); + rc= mysql_stmt_prepare(stmt, call_stmt, strlen(call_stmt)); + DIE_UNLESS(rc == 0); + + memset(&bind, 0, sizeof bind); + rc= mysql_stmt_execute(stmt); + DIE_UNLESS(rc == 0); + + mysql_stmt_close(stmt); + DIE_UNLESS(mysql_query_or_error(mysql, "DROP PROCEDURE proc") == 0); + DIE_UNLESS(mysql_query_or_error(mysql, "DROP VIEW v") == 0); + if (table_stmt && table_stmt[0] != '\0') + DIE_UNLESS(mysql_query_or_error(mysql, "DROP TABLE t") == 0); +} + +static void test_mdev_36678() +{ + const char *proc_stmt1= "CREATE OR REPLACE PROCEDURE proc(IN i VARCHAR(1)) \ + SELECT * FROM v v WHERE CASE WHEN i THEN v.l LIKE CONCAT ('',i) END;"; + const char *proc_stmt2= "CREATE OR REPLACE PROCEDURE proc(IN `IN_listc2` VARCHAR(1000), IN `IN_limitfrom` INT, IN `IN_limitto` INT) \ + BEGIN \ + SELECT * \ + FROM \ + v `t` \ + WHERE \ + CASE WHEN IN_listc2 IS NOT NULL THEN `t`.`listc2` LIKE CONCAT(\"%\", IN_listc2, \"%\") ELSE TRUE END \ + LIMIT \ + IN_limitfrom, \ + IN_limitto; \ + END;"; + + const char *table_stmt1= "CREATE OR REPLACE TABLE t (c INT) ENGINE=MyISAM;"; + const char *table_stmt2= "CREATE OR REPLACE TABLE t (c INT) ENGINE=InnoDB;"; + const char *table_stmt3= "create or replace table t \ + ( id int auto_increment primary key, col1 int, col2 int, col3 int);"; + + const char *insert_stmt1= "insert into t select null, round(rand()*100), \ + round(rand()*100), round(rand()*100) from seq_1_to_100;"; + + const char *view_stmt1= "CREATE OR REPLACE VIEW v \ + AS SELECT GROUP_CONCAT('', '') AS l FROM (SELECT 1) AS a;"; + const char *view_stmt2= "CREATE OR REPLACE VIEW v \ + AS SELECT GROUP_CONCAT('', '') AS l FROM t;"; + const char *view_stmt3= "create or replace view v as \ + select col1 as taskcid, sum(col3) as suc3, \ + group_concat('-',case when `col3` is not null then `col2` else '' end,'-' separator ',') AS `listc2` \ + from t \ + group by col1;"; + + const char *view_stmt11= "CREATE OR REPLACE VIEW v \ + AS SELECT CONCAT('', '') AS l FROM (SELECT 1) AS a;"; + const char *view_stmt21= "CREATE OR REPLACE VIEW v \ + AS SELECT CONCAT('', '') AS l FROM t;"; + const char *view_stmt31= "create or replace view v as \ + select col1 as taskcid, col3 as suc3, \ + CONCAT('-', CASE WHEN col3 IS NOT NULL THEN col2 ELSE '' END, '-') AS `listc2` \ + from t;"; + + run_tests_36678("View with GROUP_CONCAT created from derived table-", + "", "", view_stmt1, proc_stmt1, "call proc(0)"); + run_tests_36678("View with CONCAT created from derived table-", + "", "", view_stmt11, proc_stmt1, "call proc(0)"); + + run_tests_36678("View with GROUP_CONCAT created from MyISAM table-", + table_stmt1, "", view_stmt2, proc_stmt1, "call proc(0)"); + run_tests_36678("View with CONCAT created from MyISAM table-", + table_stmt1, "", view_stmt21, proc_stmt1, "call proc(0)"); + + run_tests_36678("View with GROUP_CONCAT created from InnoDB table-", + table_stmt2, "", view_stmt2, proc_stmt1, "call proc(0)"); + run_tests_36678("View with CONCAT created from InnoDB table-", + table_stmt2, "", view_stmt21, proc_stmt1, "call proc(0)"); + + run_tests_36678("View with GROUP_CONCAT created from table with data-", + table_stmt3, insert_stmt1, view_stmt3, proc_stmt2, "call proc(null, 0, 25)"); + run_tests_36678("View with CONCAT created from table with data-", + table_stmt3, insert_stmt1, view_stmt31, proc_stmt2, "call proc(null, 0, 25)"); +} + #endif // EMBEDDED_LIBRARY /* @@ -23554,6 +23660,7 @@ static struct my_tests_st my_tests[]= { { "test_mdev_34718_ad", test_mdev_34718_ad }, { "test_mdev_34958", test_mdev_34958 }, { "test_mdev_32086", test_mdev_32086 }, + { "test_mdev_36678", test_mdev_36678 }, #endif { "test_mdev_10075", test_mdev_10075}, #ifndef EMBEDDED_LIBRARY