From 85517f609a070aa9414fa8b2a1a9ff25e9bb9af8 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 11 Feb 2024 00:05:24 +0400 Subject: [PATCH 01/20] MDEV-33393 audit plugin do not report user did the action.. The '' user is assigned to the slave replication thread so this name appears in the auditing logs. --- mysql-test/suite/rpl/r/rpl_auditing.result | 64 ++++++++++++++++++ mysql-test/suite/rpl/t/rpl_auditing.test | 77 ++++++++++++++++++++++ sql/mysqld.cc | 3 +- sql/mysqld.h | 2 +- sql/slave.cc | 1 + sql/sql_acl.cc | 2 +- sql/sql_class.cc | 2 +- sql/sql_class.h | 2 + sql/sql_show.cc | 9 +-- 9 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_auditing.result create mode 100644 mysql-test/suite/rpl/t/rpl_auditing.test diff --git a/mysql-test/suite/rpl/r/rpl_auditing.result b/mysql-test/suite/rpl/r/rpl_auditing.result new file mode 100644 index 00000000000..1861beb4e8f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_auditing.result @@ -0,0 +1,64 @@ +include/master-slave.inc +[connection master] +drop table if exists t1; +connection slave; +reset master; +CREATE TABLE IF NOT EXISTS mysql.server_audit_filters ( +filtername char(80) COLLATE utf8_bin NOT NULL DEFAULT '', +rule longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT 'true' CHECK (json_valid(rule)), +CONSTRAINT c_filtername UNIQUE (filtername) +) ENGINE=Aria; +CREATE TABLE IF NOT EXISTS mysql.server_audit_users (host char(60) COLLATE utf8_bin NOT NULL DEFAULT '', +user char(80) COLLATE utf8_bin NOT NULL DEFAULT '', +filtername char(80) NOT NULL DEFAULT '', +CONSTRAINT c_host_user UNIQUE (host, user) +) ENGINE=Aria; +INSERT INTO mysql.server_audit_filters VALUES ('ignore_sys', '{"ignore_tables" : "mysql.*"}'); +INSERT INTO mysql.server_audit_users VALUES ('%','','ignore_sys'); +INSERT INTO mysql.server_audit_users VALUES ('%','root','ignore_sys'); +install plugin server_audit soname 'server_audit2'; +set global server_audit_logging=on; +connection master; +create table t1 (a int); +insert into t1 values (1); +truncate t1; +drop table t1; +connection slave; +set global server_audit_logging=off; +truncate mysql.server_audit_filters; +truncate mysql.server_audit_users; +INSERT INTO mysql.server_audit_filters VALUES ('no_logging','false'); +INSERT INTO mysql.server_audit_users VALUES ('%','','no_logging'); +set global server_audit_logging=on; +connection master; +create table t1 (a int); +insert into t1 values (1); +truncate t1; +drop table t1; +connection slave; +set global server_audit_logging=off; +uninstall plugin server_audit; +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +truncate mysql.server_audit_filters; +truncate mysql.server_audit_users; +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,file_path=server_audit.log,0 +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,rotate_size=1000000,0 +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,file_rotations=9,0 +TIME,HOSTNAME,root,localhost,ID,0,AUDIT_CONFIG,test,logging=ON,0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 +TIME,HOSTNAME,,,ID,ID,CREATE,test,t1, +TIME,HOSTNAME,,,ID,ID,WRITE,test,t1, +TIME,HOSTNAME,,,ID,ID,CREATE,test,t1, +TIME,HOSTNAME,,,ID,ID,DROP,test,t1, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select master_pos_wait(\'master-bin.#', POS, 300, \'\')',0 +TIME,HOSTNAME,root,localhost,ID,0,AUDIT_CONFIG,test,logging=OFF,0 +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,file_path=server_audit.log,0 +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,rotate_size=1000000,0 +TIME,HOSTNAME,,,0,0,AUDIT_CONFIG,,file_rotations=9,0 +TIME,HOSTNAME,root,localhost,ID,0,AUDIT_CONFIG,test,logging=ON,0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'select master_pos_wait(\'master-bin.#', POS, 300, \'\')',0 +TIME,HOSTNAME,root,localhost,ID,0,AUDIT_CONFIG,test,logging=OFF,0 +connection master; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_auditing.test b/mysql-test/suite/rpl/t/rpl_auditing.test new file mode 100644 index 00000000000..3d3cee9a7a0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_auditing.test @@ -0,0 +1,77 @@ +if (!$SERVER_AUDIT2_SO) { + skip No SERVER_AUDIT2 plugin; +} + +source include/master-slave.inc; + +--disable_warnings +drop table if exists t1; +sync_slave_with_master; +reset master; +--enable_warnings + +--disable_warnings +CREATE TABLE IF NOT EXISTS mysql.server_audit_filters ( + filtername char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + rule longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT 'true' CHECK (json_valid(rule)), + CONSTRAINT c_filtername UNIQUE (filtername) +) ENGINE=Aria; + +CREATE TABLE IF NOT EXISTS mysql.server_audit_users (host char(60) COLLATE utf8_bin NOT NULL DEFAULT '', + user char(80) COLLATE utf8_bin NOT NULL DEFAULT '', + filtername char(80) NOT NULL DEFAULT '', + CONSTRAINT c_host_user UNIQUE (host, user) +) ENGINE=Aria; +--enable_warnings + +INSERT INTO mysql.server_audit_filters VALUES ('ignore_sys', '{"ignore_tables" : "mysql.*"}'); +INSERT INTO mysql.server_audit_users VALUES ('%','','ignore_sys'); +INSERT INTO mysql.server_audit_users VALUES ('%','root','ignore_sys'); + +install plugin server_audit soname 'server_audit2'; +set global server_audit_logging=on; + +# this is done to make test deterministic +# so the above 'set' command is always logged before the 'create table t1' +-- disable_query_log +-- disable_result_log +select * from mysql.server_audit_filters; +select * from mysql.server_audit_users; +-- enable_result_log +-- enable_query_log + +connection master; +create table t1 (a int); +insert into t1 values (1); +truncate t1; +drop table t1; +sync_slave_with_master; + +set global server_audit_logging=off; + +truncate mysql.server_audit_filters; +truncate mysql.server_audit_users; +INSERT INTO mysql.server_audit_filters VALUES ('no_logging','false'); +INSERT INTO mysql.server_audit_users VALUES ('%','','no_logging'); + +set global server_audit_logging=on; + +connection master; +create table t1 (a int); +insert into t1 values (1); +truncate t1; +drop table t1; +sync_slave_with_master; + +set global server_audit_logging=off; +uninstall plugin server_audit; +truncate mysql.server_audit_filters; +truncate mysql.server_audit_users; +let $MYSQLD_DATADIR= `SELECT @@datadir`; +# replace the timestamp and the hostname with constant values +--replace_regex /[0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9]\,[^,]*\,/TIME,HOSTNAME,/ /\,[1-9][0-9]*\,/,1,/ /\,[1-9][0-9]*/,ID/ /000001\\', [0-9]*,/#', POS,/ +cat_file $MYSQLD_DATADIR/server_audit.log; +remove_file $MYSQLD_DATADIR/server_audit.log; + +connection master; +--source include/rpl_end.inc diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 82bed1ccff2..f03e5780ad9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -297,7 +297,8 @@ static TYPELIB tc_heuristic_recover_typelib= }; const char *first_keyword= "first"; -const char *my_localhost= "localhost", *delayed_user= "DELAYED"; +const char *my_localhost= "localhost", + *delayed_user= "delayed", *slave_user= ""; bool opt_large_files= sizeof(my_off_t) > 4; static my_bool opt_autocommit; ///< for --autocommit command-line option diff --git a/sql/mysqld.h b/sql/mysqld.h index 8d26bcbb5f0..5fa8e22c2ab 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -264,7 +264,7 @@ extern time_t server_start_time, flush_status_time; extern char *opt_mysql_tmpdir, mysql_charsets_dir[]; extern size_t mysql_unpacked_real_data_home_len; extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; -extern const char *first_keyword, *delayed_user; +extern const char *first_keyword, *delayed_user, *slave_user; extern MYSQL_PLUGIN_IMPORT const char *my_localhost; extern MYSQL_PLUGIN_IMPORT const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; diff --git a/sql/slave.cc b/sql/slave.cc index 3726bc1a6f6..f70336e980a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3511,6 +3511,7 @@ static int init_slave_thread(THD* thd, Master_info *mi, } thd->security_ctx->skip_grants(); + thd->security_ctx->user=(char*) slave_user; thd->slave_thread= 1; thd->connection_name= mi->connection_name; thd->variables.sql_log_slow= !MY_TEST(thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 39b1be87040..1c207cd54eb 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7532,7 +7532,7 @@ static bool can_grant_role(THD *thd, ACL_ROLE *role) { Security_context *sctx= thd->security_ctx; - if (!sctx->user) // replication + if (!sctx->is_user_defined()) // galera return true; ACL_USER *grantee= find_user_exact(sctx->priv_host, sctx->priv_user); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a358d9c3351..ad8e961d6d8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4504,7 +4504,7 @@ void Security_context::destroy() my_free((char*) host); host= NULL; } - if (user != delayed_user) + if (is_user_defined()) { my_free((char*) user); user= NULL; diff --git a/sql/sql_class.h b/sql/sql_class.h index a8ef8648210..f887a6cfa92 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1506,6 +1506,8 @@ public: */ bool check_access(const privilege_t want_access, bool match_any = false); bool is_priv_user(const char *user, const char *host); + bool is_user_defined() const + { return user && user != delayed_user && user != slave_user; }; }; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9f1dee1f598..63c00f8614e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2776,9 +2776,10 @@ static my_bool list_callback(THD *tmp, list_callback_arg *arg) thd_info->thread_id=tmp->thread_id; thd_info->os_thread_id=tmp->os_thread_id; - thd_info->user= arg->thd->strdup(tmp_sctx->user ? tmp_sctx->user : - (tmp->system_thread ? - "system user" : "unauthenticated user")); + thd_info->user= arg->thd->strdup(tmp_sctx->user && tmp_sctx->user != slave_user ? + tmp_sctx->user : + (tmp->system_thread ? + "system user" : "unauthenticated user")); if (tmp->peer_port && (tmp_sctx->host || tmp_sctx->ip) && arg->thd->security_ctx->host_or_ip[0]) { @@ -3225,7 +3226,7 @@ static my_bool processlist_callback(THD *tmp, processlist_callback_arg *arg) /* ID */ arg->table->field[0]->store((longlong) tmp->thread_id, TRUE); /* USER */ - val= tmp_sctx->user ? tmp_sctx->user : + val= tmp_sctx->user && tmp_sctx->user != slave_user ? tmp_sctx->user : (tmp->system_thread ? "system user" : "unauthenticated user"); arg->table->field[1]->store(val, strlen(val), cs); /* HOST */ From 0185ac64f390528ec89b4be6d970c4f5c54fbe08 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Thu, 11 Jan 2024 10:02:58 -0500 Subject: [PATCH 02/20] MDEV-30975 Wrong result with cross Join given join order For queries with derived tables populated having some side-effect, we will fill such a derived table more than once, but without clearing its rows. Consequently it will have duplicate rows. An example query exhibiting the problem is SELECT STRAIGHT_JOIN c1 FROM t1 JOIN (SELECT @a := 0) x; Since mysql_derived_fill will, for UNCACHEABLE_DEPENDENT tables, drop all rows and repopulate, we relax the condition at line 1204: rather than assume all uncacheable values prevent early return, we now allow an early return for uncacheable values other than UNCACHEABLE_DEPENDENT. In general, we only populate derived tables once unless they're dependent tables. --- mysql-test/main/join.result | 56 +++++++++++++++++++++++++++++++++++++ mysql-test/main/join.test | 46 ++++++++++++++++++++++++++++++ sql/sql_derived.cc | 9 ++++-- 3 files changed, 109 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/join.result b/mysql-test/main/join.result index e4b92b4234b..07579a065f9 100644 --- a/mysql-test/main/join.result +++ b/mysql-test/main/join.result @@ -3423,6 +3423,62 @@ SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2. COUNT(*) 2 DROP TABLE t1, t2, t3; +# +# MDEV-30975: Wrong result with cross Join given join order +# +CREATE TABLE `t1` ( +`t1_seq` INT NOT NULL, +`c1` VARCHAR(10) NOT NULL , +PRIMARY KEY (`t1_seq`) USING BTREE +); +CREATE TABLE `t2` ( +`t2_seq` INT NOT NULL, +`t1_seq` INT NOT NULL, +`c2` VARCHAR(10) NOT NULL , +PRIMARY KEY (`t2_seq`, `t1_seq`) USING BTREE +); +INSERT INTO t1 VALUES(1, 'A'); +INSERT INTO t2 VALUES(1, 1, 'T2-1-1'); +INSERT INTO t2 VALUES(2, 1, 'T2-1-2'); +INSERT INTO t2 VALUES(3, 1, 'T2-1-3'); +SELECT LPAD(@rownum := @rownum + 1, 8, 0) AS str_num +, t1.t1_seq +, t2.t2_seq +, t1.c1 +, t2.c2 +FROM t1 +INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq) +CROSS JOIN ( SELECT @rownum := 0 ) X; +str_num t1_seq t2_seq c1 c2 +00000001 1 1 A T2-1-1 +00000002 1 2 A T2-1-2 +00000003 1 3 A T2-1-3 +SELECT STRAIGHT_JOIN LPAD(@rownum := @rownum + 1, 8, 0) AS str_num +, t1.t1_seq +, t2.t2_seq +, t1.c1 +, t2.c2 +FROM t1 +INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq) +CROSS JOIN ( SELECT @rownum := 0 ) X; +str_num t1_seq t2_seq c1 c2 +00000001 1 1 A T2-1-1 +00000002 1 2 A T2-1-2 +00000003 1 3 A T2-1-3 +SELECT STRAIGHT_JOIN * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x; +t1_seq c1 t2_seq t1_seq c2 @a := 0 +1 A 1 1 T2-1-1 0 +1 A 2 1 T2-1-2 0 +1 A 3 1 T2-1-3 0 +SELECT * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x; +t1_seq c1 t2_seq t1_seq c2 @a := 0 +1 A 1 1 T2-1-1 0 +1 A 2 1 T2-1-2 0 +1 A 3 1 T2-1-3 0 +SELECT STRAIGHT_JOIN c1 FROM t1 JOIN (SELECT @a := 0) x; +c1 +A +DROP TABLE t1, t2; # End of 10.5 tests # # MDEV-31449: Assertion s->table->opt_range_condition_rows <= s->found_records diff --git a/mysql-test/main/join.test b/mysql-test/main/join.test index 2f94daf4616..f8abc3fac22 100644 --- a/mysql-test/main/join.test +++ b/mysql-test/main/join.test @@ -1838,6 +1838,52 @@ SELECT * FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; SELECT COUNT(*) FROM t1 LEFT JOIN (t2 LEFT JOIN t3 ON t2.b = t3.c) ON t1.a = t2.b; DROP TABLE t1, t2, t3; +--echo # +--echo # MDEV-30975: Wrong result with cross Join given join order +--echo # + +CREATE TABLE `t1` ( + `t1_seq` INT NOT NULL, + `c1` VARCHAR(10) NOT NULL , + PRIMARY KEY (`t1_seq`) USING BTREE +); + +CREATE TABLE `t2` ( + `t2_seq` INT NOT NULL, + `t1_seq` INT NOT NULL, + `c2` VARCHAR(10) NOT NULL , + PRIMARY KEY (`t2_seq`, `t1_seq`) USING BTREE +); + +INSERT INTO t1 VALUES(1, 'A'); +INSERT INTO t2 VALUES(1, 1, 'T2-1-1'); +INSERT INTO t2 VALUES(2, 1, 'T2-1-2'); +INSERT INTO t2 VALUES(3, 1, 'T2-1-3'); + +SELECT LPAD(@rownum := @rownum + 1, 8, 0) AS str_num + , t1.t1_seq + , t2.t2_seq + , t1.c1 + , t2.c2 + FROM t1 + INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq) + CROSS JOIN ( SELECT @rownum := 0 ) X; + +SELECT STRAIGHT_JOIN LPAD(@rownum := @rownum + 1, 8, 0) AS str_num + , t1.t1_seq + , t2.t2_seq + , t1.c1 + , t2.c2 + FROM t1 + INNER JOIN t2 ON (t1.t1_seq = t2.t1_seq) + CROSS JOIN ( SELECT @rownum := 0 ) X; + +SELECT STRAIGHT_JOIN * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x; +SELECT * FROM t1 JOIN t2 ON (t1.t1_seq = t2.t1_seq) JOIN (SELECT @a := 0) x; +SELECT STRAIGHT_JOIN c1 FROM t1 JOIN (SELECT @a := 0) x; + +DROP TABLE t1, t2; + --echo # End of 10.5 tests --echo # diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index e0f3ec18bf0..a721875051b 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1201,8 +1201,12 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) (derived->alias.str ? derived->alias.str : ""), derived->get_unit())); - if (unit->executed && !unit->uncacheable && !unit->describe && - !derived_is_recursive) + /* + Only fill derived tables once, unless the derived table is dependent in + which case we will delete all of its rows and refill it below. + */ + if (unit->executed && !(unit->uncacheable & UNCACHEABLE_DEPENDENT) && + !unit->describe && !derived_is_recursive) DBUG_RETURN(FALSE); /*check that table creation passed without problems. */ DBUG_ASSERT(derived->table && derived->table->is_created()); @@ -1261,6 +1265,7 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) } else { + DBUG_ASSERT(!unit->executed || (unit->uncacheable & UNCACHEABLE_DEPENDENT)); SELECT_LEX *first_select= unit->first_select(); unit->set_limit(unit->global_parameters()); if (unit->lim.is_unlimited()) From 8a1904d7825f9897cd237fc6a1d8a57a9f2108de Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 25 Jan 2024 16:07:51 +1100 Subject: [PATCH 03/20] MDEV-33301 memlock with systemd still not working CapabilityBoundingSet included CAP_IPC_LOCK in MDEV-9095, however it requires that the executable has the capability marked in extended attributes also. The alternate to this is raising the RLIMIT_MEMLOCK for the service/ process to be able to complete the mlockall system call. This needs to be adjusted to whatever the MariaDB server was going to allocate. Rather than leave the non-obvious mapping of settings and tuning, add the capability so its easier for the user. We set the capability, if possible, but may never be used depending on user settings. As such in the Debian postinst script, don't complain if this fails. The CAP_IPC_LOCK also facilitates the mmaping of huge memory pages. (see man mmap), like mariadb uses with --large-pages. --- cmake/cpack_rpm.cmake | 1 + debian/mariadb-server-core-10.5.postinst | 26 +++++++++++++++++++ support-files/policy/apparmor/usr.sbin.mysqld | 1 + .../policy/selinux/mariadb-server.te | 4 ++- 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 debian/mariadb-server-core-10.5.postinst diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 65a739dc03e..414b4f6a902 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -163,6 +163,7 @@ SET(CPACK_RPM_server_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONF2DIR}/*" "%config(noreplace) ${INSTALL_SYSCONFDIR}/logrotate.d/mysql" + "%caps(cap_ipc_lock=pe) %{_sbindir}/mysqld" ) SET(CPACK_RPM_common_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONFDIR}/my.cnf") SET(CPACK_RPM_shared_USER_FILELIST ${ignored} "%config(noreplace) ${INSTALL_SYSCONF2DIR}/*") diff --git a/debian/mariadb-server-core-10.5.postinst b/debian/mariadb-server-core-10.5.postinst new file mode 100644 index 00000000000..5f79bed2402 --- /dev/null +++ b/debian/mariadb-server-core-10.5.postinst @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +# inspired by iputils-ping +# +# cap_ipc_lock is required if a user wants to use --memlock +# and has insufficient RLIMIT_MEMLOCK (MDEV-33301) + +PROGRAM=$(dpkg-divert --truename /usr/sbin/mysqld) + +if [ "$1" = configure ]; then + # If we have setcap installed, try setting + # which allows us to install our binaries without the setuid + # bit. + if command -v setcap > /dev/null; then + if ! setcap cap_ipc_lock+ep "$PROGRAM"; then + echo "Setcap failed on $PROGRAM, required with --memlock if insufficent RLIMIT_MEMLOCK" >&2 + fi + fi +fi + + +#DEBHELPER# + +exit 0 diff --git a/support-files/policy/apparmor/usr.sbin.mysqld b/support-files/policy/apparmor/usr.sbin.mysqld index c60ecd28531..732f4b3a97a 100644 --- a/support-files/policy/apparmor/usr.sbin.mysqld +++ b/support-files/policy/apparmor/usr.sbin.mysqld @@ -14,6 +14,7 @@ capability chown, capability dac_override, + capability ipc_lock, capability setgid, capability setuid, capability sys_rawio, diff --git a/support-files/policy/selinux/mariadb-server.te b/support-files/policy/selinux/mariadb-server.te index 89846063506..ba53c97d4a8 100644 --- a/support-files/policy/selinux/mariadb-server.te +++ b/support-files/policy/selinux/mariadb-server.te @@ -25,7 +25,7 @@ require { class lnk_file read; class process { getattr signull }; class unix_stream_socket connectto; - class capability { sys_resource sys_nice }; + class capability { ipc_lock sys_resource sys_nice }; class tcp_socket { name_bind name_connect }; class file { execute setattr read create getattr execute_no_trans write ioctl open append unlink }; class sock_file { create unlink getattr }; @@ -87,6 +87,8 @@ allow mysqld_t bin_t:file { getattr read execute open execute_no_trans ioctl }; # MariaDB additions allow mysqld_t self:process setpgid; +allow mysqld_t self:capability { ipc_lock }; + # This rule allows port tcp/4444 allow mysqld_t kerberos_port_t:tcp_socket { name_bind name_connect }; # This rule allows port tcp/4567 (tram_port_t may not be available on From d510f80549121ac2a07588b5ee9d0252e2b3b60f Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 10 Feb 2024 00:30:47 +0100 Subject: [PATCH 04/20] MDEV-33482: Optimize WolfSSL for improved performance - Use "new" math library WOLFSSL_SP_MATH_ALL, which is now promoted by WolfSSL for faster performance. "fastmath" we used previously is going to be deprecated, it was not really always fast. - Optimize common RSA math operations with WOLFSSL_HAVE_SP_RSA - Incorporate assembly optimizations, currently for Intel x64 only This patch significantly reduces execution time for SSL tests like main.ssl-big and main.ssl_connect, which now run 2 to 3 times faster. Notably, when this patch is applied to 11.4, server startup in with ephemeral certificates becomes approximately 10x faster due to optimized wolfSSL_EVP_PKEY_keygen(). Additionally, refactored WolfSSL by removing old workarounds and consolidating wolfssl and wolfcrypt into a single library wolfssl, just like it was done in WolfSSL's own CMake. --- cmake/os/Windows.cmake | 8 ++ cmake/ssl.cmake | 2 +- extra/wolfssl/CMakeLists.txt | 192 ++++++++++++------------------- extra/wolfssl/user_settings.h.in | 18 +-- 4 files changed, 93 insertions(+), 127 deletions(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index f47d4ebc98d..1a853349ae5 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -24,6 +24,14 @@ INCLUDE (CheckCSourceRuns) INCLUDE (CheckSymbolExists) INCLUDE (CheckTypeSize) +IF(MSVC) + IF(CMAKE_CXX_COMPILER_ARCHITECTURE_ID STREQUAL ARM64) + SET(MSVC_ARM64 1) + SET(MSVC_INTEL 0) + ELSE() + SET(MSVC_INTEL 1) + ENDIF() +ENDIF() # avoid running system checks by using pre-cached check results # system checks are expensive on VS since every tiny program is to be compiled in diff --git a/cmake/ssl.cmake b/cmake/ssl.cmake index 646aa37a91c..51176a84c51 100644 --- a/cmake/ssl.cmake +++ b/cmake/ssl.cmake @@ -53,7 +53,7 @@ MACRO (MYSQL_USE_BUNDLED_SSL) ${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl ${CMAKE_SOURCE_DIR}/extra/wolfssl/wolfssl/wolfssl ) - SET(SSL_LIBRARIES wolfssl wolfcrypt) + SET(SSL_LIBRARIES wolfssl) SET(SSL_INCLUDE_DIRS ${INC_DIRS}) SET(SSL_DEFINES "-DHAVE_OPENSSL -DHAVE_WOLFSSL -DWOLFSSL_USER_SETTINGS") SET(HAVE_ERR_remove_thread_state ON CACHE INTERNAL "wolfssl doesn't have ERR_remove_thread_state") diff --git a/extra/wolfssl/CMakeLists.txt b/extra/wolfssl/CMakeLists.txt index 69f7801d4e3..e3f8da21f76 100644 --- a/extra/wolfssl/CMakeLists.txt +++ b/extra/wolfssl/CMakeLists.txt @@ -1,86 +1,57 @@ -IF(MSVC) +IF(MSVC_INTEL) PROJECT(wolfssl C ASM_MASM) ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") - PROJECT(wolfssl C ASM) + PROJECT(wolfssl C ASM) ELSE() PROJECT(wolfssl C) ENDIF() IF(CMAKE_SIZEOF_VOID_P MATCHES 8) -IF(MSVC) +IF(MSVC_INTEL AND NOT (CMAKE_C_COMPILER_ID MATCHES Clang)) SET(WOLFSSL_INTELASM ON) - SET(WOLFSSL_X86_64_BUILD 1) SET(HAVE_INTEL_RDSEED 1) SET(HAVE_INTEL_RDRAND 1) -ELSEIF(CMAKE_ASM_COMPILER_ID MATCHES "Clang" AND CMAKE_VERSION VERSION_LESS 3.16) - - # WolfSSL 5.5.4 bug workaround below does not work, due to some CMake bug ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64") - SET(WOLFSSL_X86_64_BUILD 1) IF(CMAKE_C_COMPILER_ID MATCHES GNU AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) MESSAGE_ONCE(NO_INTEL_ASSEMBLY "Disable Intel assembly for WolfSSL - compiler is too old") + ELSEIF(WITH_MSAN) + MESSAGE_ONCE(MSAN_CANT_HANDLE_IT "Disable Intel assembly for WolfSSL - MSAN can't handle it") ELSE() - IF(WITH_MSAN) - MESSAGE_ONCE(MSAN_CANT_HANDLE_IT - "Disable Intel assembly for WolfSSL - MSAN can't handle it") - ELSE() - MY_CHECK_C_COMPILER_FLAG(-maes) - MY_CHECK_C_COMPILER_FLAG(-msse4) - MY_CHECK_C_COMPILER_FLAG(-mpclmul) - IF(have_C__maes AND have_C__msse4 AND have_C__mpclmul) - SET(WOLFSSL_INTELASM ON) + MY_CHECK_C_COMPILER_FLAG(-maes) + MY_CHECK_C_COMPILER_FLAG(-msse4) + MY_CHECK_C_COMPILER_FLAG(-mpclmul) + IF(have_C__maes AND have_C__msse4 AND have_C__mpclmul) + SET(WOLFSSL_INTELASM ON) + MY_CHECK_C_COMPILER_FLAG(-mrdrnd) + MY_CHECK_C_COMPILER_FLAG(-mrdseed) + IF(have_C__mrdrnd) + SET(HAVE_INTEL_RDRAND ON) + ENDIF() + IF(have_C__mrdseed) + SET(HAVE_INTEL_RDSEED ON) ENDIF() - ENDIF() - MY_CHECK_C_COMPILER_FLAG(-mrdrnd) - MY_CHECK_C_COMPILER_FLAG(-mrdseed) - IF(have_C__mrdrnd) - SET(HAVE_INTEL_RDRAND ON) - ENDIF() - IF(have_C__mrdseed) - SET(HAVE_INTEL_RDSEED ON) ENDIF() ENDIF() ENDIF() ENDIF() SET(WOLFSSL_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/src) -ADD_DEFINITIONS(${SSL_DEFINES}) - -SET(WOLFSSL_SOURCES - ${WOLFSSL_SRCDIR}/crl.c - ${WOLFSSL_SRCDIR}/internal.c - ${WOLFSSL_SRCDIR}/keys.c - ${WOLFSSL_SRCDIR}/tls.c - ${WOLFSSL_SRCDIR}/wolfio.c - ${WOLFSSL_SRCDIR}/ocsp.c - ${WOLFSSL_SRCDIR}/ssl.c - ${WOLFSSL_SRCDIR}/tls13.c) - -ADD_DEFINITIONS(-DWOLFSSL_LIB -DBUILDING_WOLFSSL) - -INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl) -IF(MSVC) - # size_t to long truncation warning - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd4267 -wd4334 -wd4028 -wd4244") -ENDIF() - -ADD_CONVENIENCE_LIBRARY(wolfssl ${WOLFSSL_SOURCES}) - -# Workaround linker crash with older Ubuntu binutils -# e.g aborting at ../../bfd/merge.c line 873 in _bfd_merged_section_offset -IF(CMAKE_SYSTEM_NAME MATCHES "Linux") - STRING(REPLACE "-g " "-g1 " CMAKE_C_FLAGS_RELWITHDEBINFO - ${CMAKE_C_FLAGS_RELWITHDEBINFO}) - STRING(REPLACE "-g " "-g1 " CMAKE_C_FLAGS_DEBUG - ${CMAKE_C_FLAGS_DEBUG}) - STRING(REPLACE "-ggdb3 " " " CMAKE_C_FLAGS_RELWITHDEBINFO - ${CMAKE_C_FLAGS_RELWITHDEBINFO}) - STRING(REPLACE "-ggdb3 " " " CMAKE_C_FLAGS_DEBUG - ${CMAKE_C_FLAGS_DEBUG}) -ENDIF() - SET(WOLFCRYPT_SRCDIR ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl/wolfcrypt/src) -SET(WOLFCRYPT_SOURCES +ADD_DEFINITIONS(${SSL_DEFINES}) +ADD_DEFINITIONS(-DWOLFSSL_LIB -DBUILDING_WOLFSSL) +ADD_DEFINITIONS(-DWOLFSSL_SP_4096) +INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/wolfssl) +INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS}) + +add_library(wolfssl STATIC +${WOLFSSL_SRCDIR}/crl.c +${WOLFSSL_SRCDIR}/internal.c +${WOLFSSL_SRCDIR}/keys.c +${WOLFSSL_SRCDIR}/tls.c +${WOLFSSL_SRCDIR}/wolfio.c +${WOLFSSL_SRCDIR}/ocsp.c +${WOLFSSL_SRCDIR}/ssl.c +${WOLFSSL_SRCDIR}/tls13.c ${WOLFCRYPT_SRCDIR}/aes.c ${WOLFCRYPT_SRCDIR}/arc4.c ${WOLFCRYPT_SRCDIR}/asn.c @@ -110,69 +81,56 @@ ${WOLFCRYPT_SRCDIR}/wc_encrypt.c ${WOLFCRYPT_SRCDIR}/hash.c ${WOLFCRYPT_SRCDIR}/wolfmath.c ${WOLFCRYPT_SRCDIR}/kdf.c +${WOLFCRYPT_SRCDIR}/sp_int.c +${WOLFCRYPT_SRCDIR}/sp_c32.c +${WOLFCRYPT_SRCDIR}/sp_c64.c ) -# Use fastmath large number math library. -IF(NOT (MSVC AND CMAKE_C_COMPILER_ID MATCHES Clang)) - # Can't use clang-cl with WOLFSSL_FASTMATH - # due to https://bugs.llvm.org/show_bug.cgi?id=25305 - SET(WOLFSSL_FASTMATH 1) -ENDIF() - -IF(WOLFSSL_FASTMATH) - SET(USE_FAST_MATH 1) - SET(TFM_TIMING_RESISTANT 1) - # FP_MAX_BITS is set high solely to satisfy ssl_8k_key.test - # WolfSSL will use more stack space with it - SET(FP_MAX_BITS 16384) - SET(WOLFCRYPT_SOURCES ${WOLFCRYPT_SOURCES} ${WOLFCRYPT_SRCDIR}/tfm.c) - IF((CMAKE_SIZEOF_VOID_P MATCHES 4) AND (CMAKE_SYSTEM_PROCESSOR MATCHES "86") - AND (NOT MSVC)) - # Workaround https://github.com/wolfSSL/wolfssl/issues/4245 - # On 32bit Intel, to satisfy inline assembly's wish for free registers - # 1. use -fomit-frame-pointer - # 2. With GCC 4, additionally use -fno-PIC, which works on x86 - # (modern GCC has PIC optimizations, that make it unnecessary) - # The following assumes GCC or Clang - SET(TFM_COMPILE_FLAGS "-fomit-frame-pointer") - IF(CMAKE_C_COMPILER_VERSION VERSION_LESS "5") - SET(TFM_COMPILE_FLAGS "${TFM_COMPILE_FLAGS} -fno-PIC") - ENDIF() - SET_SOURCE_FILES_PROPERTIES(${WOLFCRYPT_SRCDIR}/tfm.c - PROPERTIES COMPILE_FLAGS ${TFM_COMPILE_FLAGS}) - ENDIF() -ELSE() - SET(WOLFSSL_SP_MATH_ALL 1) - SET(WOLFCRYPT_SOURCES ${WOLFCRYPT_SOURCES} ${WOLFCRYPT_SRCDIR}/sp_int.c) -ENDIF() - -IF(WOLFSSL_X86_64_BUILD) - LIST(APPEND WOLFCRYPT_SOURCES ${WOLFCRYPT_SRCDIR}/cpuid.c) - IF(MSVC) - SET(WOLFSSL_AESNI 1) - LIST(APPEND WOLFCRYPT_SOURCES - ${WOLFCRYPT_SRCDIR}/aes_asm.asm - ${WOLFCRYPT_SRCDIR}/aes_gcm_asm.asm) - IF(CMAKE_C_COMPILER_ID MATCHES Clang) - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes -msse4.2 -mpclmul -mrdrnd -mrdseed") - ENDIF() - ELSEIF(WOLFSSL_INTELASM) - SET(WOLFSSL_AESNI 1) - SET(USE_INTEL_SPEEDUP 1) - LIST(APPEND WOLFCRYPT_SOURCES +# Optimizations, assembly +if(WOLFSSL_INTELASM) + set(WOLFSSL_X86_64_BUILD 1) + set(WOLFSSL_SP_X86_64 1) + set(WOLFSSL_SP_X86_64_ASM 1) + set(WOLFSSL_AESNI 1) + target_sources(wolfssl PRIVATE + ${WOLFCRYPT_SRCDIR}/cpuid.c + ${WOLFCRYPT_SRCDIR}/sp_x86_64.c + ) + if(MSVC_INTEL) + target_sources(wolfssl PRIVATE + ${WOLFCRYPT_SRCDIR}/aes_asm.asm + ${WOLFCRYPT_SRCDIR}/aes_gcm_asm.asm + ${WOLFCRYPT_SRCDIR}/sp_x86_64_asm.asm + ) + target_compile_options(wolfssl PRIVATE + $<$:-maes -msse4.2 -mpclmul -mrdrnd -mrdseed> + $<$:/Zi> + ) + else() + set(USE_INTEL_SPEEDUP 1) + target_sources(wolfssl PRIVATE ${WOLFCRYPT_SRCDIR}/aes_asm.S ${WOLFCRYPT_SRCDIR}/aes_gcm_asm.S ${WOLFCRYPT_SRCDIR}/chacha_asm.S ${WOLFCRYPT_SRCDIR}/poly1305_asm.S ${WOLFCRYPT_SRCDIR}/sha512_asm.S - ${WOLFCRYPT_SRCDIR}/sha256_asm.S) - ADD_DEFINITIONS(-maes -msse4.2 -mpclmul) - # WolfSSL 5.5.4 bug - user_settings.h not included into aes_asm.S - SET_PROPERTY(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD") - ENDIF() -ENDIF() + ${WOLFCRYPT_SRCDIR}/sha256_asm.S + ${WOLFCRYPT_SRCDIR}/sp_x86_64_asm.S + ) + target_compile_options(wolfssl PRIVATE -maes -msse4.2 -mpclmul) + # Workaround 5.5.4 bug (user_settings.h not included into aes_asm.S) + set_property(SOURCE ${WOLFCRYPT_SRCDIR}/aes_asm.S APPEND PROPERTY COMPILE_OPTIONS "-DWOLFSSL_X86_64_BUILD") + endif() +endif() + +# Silence some warnings +if(MSVC) + # truncation warnings + target_compile_options(wolfssl PRIVATE $<$:/wd4244>) + if(CMAKE_C_COMPILER_ID MATCHES Clang) + target_compile_options(wolfssl PRIVATE $<$:-Wno-incompatible-function-pointer-types>) + endif() +endif() CONFIGURE_FILE(user_settings.h.in user_settings.h) -INCLUDE_DIRECTORIES(${SSL_INCLUDE_DIRS}) -ADD_CONVENIENCE_LIBRARY(wolfcrypt ${WOLFCRYPT_SOURCES}) diff --git a/extra/wolfssl/user_settings.h.in b/extra/wolfssl/user_settings.h.in index baa64fcdfbe..489118b33b4 100644 --- a/extra/wolfssl/user_settings.h.in +++ b/extra/wolfssl/user_settings.h.in @@ -21,6 +21,7 @@ #define HAVE_AESGCM #define HAVE_CHACHA #define HAVE_POLY1305 +#define HAVE_THREAD_LS #define WOLFSSL_AES_COUNTER #define NO_WOLFSSL_STUB #define OPENSSL_ALL @@ -51,20 +52,19 @@ #define NO_RABBIT #define NO_RC4 -/* - FP_MAX_BITS is set high solely to satisfy ssl_8k_key.test - WolfSSL will use more stack space with it, with fastmath -*/ -#cmakedefine FP_MAX_BITS 16384 #define RSA_MAX_SIZE 8192 +#define WOLFSSL_SP_MATH_ALL +#define WOLFSSL_HAVE_SP_RSA +#ifndef WOLFSSL_SP_4096 +#define WOLFSSL_SP_4096 +#endif + #cmakedefine WOLFSSL_AESNI -#cmakedefine USE_FAST_MATH -#cmakedefine TFM_TIMING_RESISTANT #cmakedefine HAVE_INTEL_RDSEED #cmakedefine HAVE_INTEL_RDRAND #cmakedefine USE_INTEL_SPEEDUP -#cmakedefine USE_FAST_MATH #cmakedefine WOLFSSL_X86_64_BUILD -#cmakedefine WOLFSSL_SP_MATH_ALL +#cmakedefine WOLFSSL_SP_X86_64 +#cmakedefine WOLFSSL_SP_X86_64_ASM #endif /* WOLFSSL_USER_SETTINGS_H */ From c492c34f67f89c2575b8f2789962359bce4d0a00 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 19 Feb 2024 15:12:16 +1100 Subject: [PATCH 05/20] MDEV-33434 spider direct sql: Check length before memcpy similar to MDEV-30981 --- .../spider/bugfix/r/mdev_33434.result | 12 ++ .../spider/bugfix/t/mdev_33434.test | 15 ++ storage/spider/spd_direct_sql.cc | 135 +++++++----------- 3 files changed, 80 insertions(+), 82 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_33434.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_33434.test diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_33434.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_33434.result new file mode 100644 index 00000000000..2cbcff38752 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_33434.result @@ -0,0 +1,12 @@ +# +# MDEV-33434 MDEV-33434 UBSAN null pointer passed as argument 2, which is declared to never be null in spider_udf_direct_sql_create_conn +# +INSTALL SONAME 'ha_spider'; +SET character_set_connection=ucs2; +SELECT SPIDER_DIRECT_SQL('SELECT SLEEP(1)', '', 'srv "dummy", port "3307"'); +ERROR HY000: Unable to connect to foreign data source: localhost +Warnings: +Warning 1620 Plugin is busy and will be uninstalled on shutdown +# +# end of test mdev_33434 +# diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_33434.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_33434.test new file mode 100644 index 00000000000..dd9f882f42e --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_33434.test @@ -0,0 +1,15 @@ +--echo # +--echo # MDEV-33434 MDEV-33434 UBSAN null pointer passed as argument 2, which is declared to never be null in spider_udf_direct_sql_create_conn +--echo # + +INSTALL SONAME 'ha_spider'; +SET character_set_connection=ucs2; +--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE +SELECT SPIDER_DIRECT_SQL('SELECT SLEEP(1)', '', 'srv "dummy", port "3307"'); +--disable_query_log +--source ../../include/clean_up_spider.inc +--enable_query_log + +--echo # +--echo # end of test mdev_33434 +--echo # diff --git a/storage/spider/spd_direct_sql.cc b/storage/spider/spd_direct_sql.cc index 2a29007a915..5de6123874f 100644 --- a/storage/spider/spd_direct_sql.cc +++ b/storage/spider/spd_direct_sql.cc @@ -413,6 +413,23 @@ int spider_udf_direct_sql_create_conn_key( DBUG_RETURN(0); } +static inline void spider_maybe_memcpy_string( + char **dest, + char *src, + char *tmp, + uint *dest_len, + uint src_len) +{ + *dest_len= src_len; + if (src_len) + { + *dest= tmp; + memcpy(*dest, src, src_len); + } else + *dest= NULL; +} + + SPIDER_CONN *spider_udf_direct_sql_create_conn( const SPIDER_DIRECT_SQL *direct_sql, int *error_num @@ -504,89 +521,43 @@ SPIDER_CONN *spider_udf_direct_sql_create_conn( { #endif conn->tgt_port = direct_sql->tgt_port; - conn->tgt_socket_length = direct_sql->tgt_socket_length; - conn->tgt_socket = tmp_socket; - memcpy(conn->tgt_socket, direct_sql->tgt_socket, - direct_sql->tgt_socket_length); + spider_maybe_memcpy_string( + &conn->tgt_socket, direct_sql->tgt_socket, tmp_socket, + &conn->tgt_socket_length, direct_sql->tgt_socket_length); if (!tables_on_different_db_are_joinable) - { - conn->tgt_db_length = direct_sql->tgt_default_db_name_length; - conn->tgt_db = tmp_db; - memcpy(conn->tgt_db, direct_sql->tgt_default_db_name, - direct_sql->tgt_default_db_name_length); - } - conn->tgt_username_length = direct_sql->tgt_username_length; - conn->tgt_username = tmp_username; - memcpy(conn->tgt_username, direct_sql->tgt_username, - direct_sql->tgt_username_length); - conn->tgt_password_length = direct_sql->tgt_password_length; - conn->tgt_password = tmp_password; - memcpy(conn->tgt_password, direct_sql->tgt_password, - direct_sql->tgt_password_length); - conn->tgt_ssl_ca_length = direct_sql->tgt_ssl_ca_length; - if (conn->tgt_ssl_ca_length) - { - conn->tgt_ssl_ca = tmp_ssl_ca; - memcpy(conn->tgt_ssl_ca, direct_sql->tgt_ssl_ca, - direct_sql->tgt_ssl_ca_length); - } else - conn->tgt_ssl_ca = NULL; - conn->tgt_ssl_capath_length = direct_sql->tgt_ssl_capath_length; - if (conn->tgt_ssl_capath_length) - { - conn->tgt_ssl_capath = tmp_ssl_capath; - memcpy(conn->tgt_ssl_capath, direct_sql->tgt_ssl_capath, - direct_sql->tgt_ssl_capath_length); - } else - conn->tgt_ssl_capath = NULL; - conn->tgt_ssl_cert_length = direct_sql->tgt_ssl_cert_length; - if (conn->tgt_ssl_cert_length) - { - conn->tgt_ssl_cert = tmp_ssl_cert; - memcpy(conn->tgt_ssl_cert, direct_sql->tgt_ssl_cert, - direct_sql->tgt_ssl_cert_length); - } else - conn->tgt_ssl_cert = NULL; - conn->tgt_ssl_cipher_length = direct_sql->tgt_ssl_cipher_length; - if (conn->tgt_ssl_cipher_length) - { - conn->tgt_ssl_cipher = tmp_ssl_cipher; - memcpy(conn->tgt_ssl_cipher, direct_sql->tgt_ssl_cipher, - direct_sql->tgt_ssl_cipher_length); - } else - conn->tgt_ssl_cipher = NULL; - conn->tgt_ssl_key_length = direct_sql->tgt_ssl_key_length; - if (conn->tgt_ssl_key_length) - { - conn->tgt_ssl_key = tmp_ssl_key; - memcpy(conn->tgt_ssl_key, direct_sql->tgt_ssl_key, - direct_sql->tgt_ssl_key_length); - } else - conn->tgt_ssl_key = NULL; - conn->tgt_default_file_length = direct_sql->tgt_default_file_length; - if (conn->tgt_default_file_length) - { - conn->tgt_default_file = tmp_default_file; - memcpy(conn->tgt_default_file, direct_sql->tgt_default_file, - direct_sql->tgt_default_file_length); - } else - conn->tgt_default_file = NULL; - conn->tgt_default_group_length = direct_sql->tgt_default_group_length; - if (conn->tgt_default_group_length) - { - conn->tgt_default_group = tmp_default_group; - memcpy(conn->tgt_default_group, direct_sql->tgt_default_group, - direct_sql->tgt_default_group_length); - } else - conn->tgt_default_group = NULL; - conn->tgt_dsn_length = direct_sql->tgt_dsn_length; - if (conn->tgt_dsn_length) - { - conn->tgt_dsn = tmp_dsn; - memcpy(conn->tgt_dsn, direct_sql->tgt_dsn, - direct_sql->tgt_dsn_length); - } else - conn->tgt_dsn = NULL; + spider_maybe_memcpy_string( + &conn->tgt_db, direct_sql->tgt_default_db_name, tmp_db, + &conn->tgt_db_length, direct_sql->tgt_default_db_name_length); + spider_maybe_memcpy_string( + &conn->tgt_username, direct_sql->tgt_username, tmp_username, + &conn->tgt_username_length, direct_sql->tgt_username_length); + spider_maybe_memcpy_string( + &conn->tgt_password, direct_sql->tgt_password, tmp_password, + &conn->tgt_password_length, direct_sql->tgt_password_length); + spider_maybe_memcpy_string( + &conn->tgt_ssl_ca, direct_sql->tgt_ssl_ca, tmp_ssl_ca, + &conn->tgt_ssl_ca_length, direct_sql->tgt_ssl_ca_length); + spider_maybe_memcpy_string( + &conn->tgt_ssl_capath, direct_sql->tgt_ssl_capath, tmp_ssl_capath, + &conn->tgt_ssl_capath_length, direct_sql->tgt_ssl_capath_length); + spider_maybe_memcpy_string( + &conn->tgt_ssl_cert, direct_sql->tgt_ssl_cert, tmp_ssl_cert, + &conn->tgt_ssl_cert_length, direct_sql->tgt_ssl_cert_length); + spider_maybe_memcpy_string( + &conn->tgt_ssl_cipher, direct_sql->tgt_ssl_cipher, tmp_ssl_cipher, + &conn->tgt_ssl_cipher_length, direct_sql->tgt_ssl_cipher_length); + spider_maybe_memcpy_string( + &conn->tgt_ssl_key, direct_sql->tgt_ssl_key, tmp_ssl_key, + &conn->tgt_ssl_key_length, direct_sql->tgt_ssl_key_length); + spider_maybe_memcpy_string( + &conn->tgt_default_file, direct_sql->tgt_default_file, tmp_default_file, + &conn->tgt_default_file_length, direct_sql->tgt_default_file_length); + spider_maybe_memcpy_string( + &conn->tgt_default_group, direct_sql->tgt_default_group, tmp_default_group, + &conn->tgt_default_group_length, direct_sql->tgt_default_group_length); + spider_maybe_memcpy_string( + &conn->tgt_dsn, direct_sql->tgt_dsn, tmp_dsn, + &conn->tgt_dsn_length, direct_sql->tgt_dsn_length); conn->tgt_ssl_vsc = direct_sql->tgt_ssl_vsc; #if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET) } else { From 75c0f9512a11088eeddbcfa0c07484c0628cf28a Mon Sep 17 00:00:00 2001 From: Andrew Daugherity Date: Tue, 21 Nov 2023 19:43:52 -0600 Subject: [PATCH 06/20] fix markdown headings Should be h2 rather than h1, and GitHub requires an intervening space. --- plugin/auth_gssapi/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugin/auth_gssapi/README.md b/plugin/auth_gssapi/README.md index ea8deaafa94..635982234c4 100644 --- a/plugin/auth_gssapi/README.md +++ b/plugin/auth_gssapi/README.md @@ -49,7 +49,7 @@ Usually nothing need to be done. MariaDB server should to run on a domain joine Creating service principal is not required here (but you can still do it using [_setspn_](https://technet.microsoft.com/en-us/library/cc731241.aspx) tool) -# Installing plugin +## Installing plugin - Start the server - On Unix, edit my the my.cnf/my.ini configuration file, set the parameter gssapi-keytab-path to point to previously @@ -72,7 +72,7 @@ configure alternative principal name with INSTALL SONAME 'auth_gssapi' ``` -#Creating users +## Creating users Now, you can create a user for GSSAPI/SSPI authentication. CREATE USER command, for Kerberos user would be like this (*long* form, see below for short one) @@ -94,7 +94,7 @@ CREATE USER usr1 IDENTIFIED WITH gssapi; If this syntax is used, realm part is *not* used for comparison thus 'usr1@EXAMPLE.COM', 'usr1@EXAMPLE.CO.UK' and 'mymachine\usr1' will all identify as 'usr1'. -#Login as GSSAPI user with command line clients +## Login as GSSAPI user with command line clients Using command line client, do @@ -102,7 +102,7 @@ Using command line client, do mysql --plugin-dir=/path/to/plugin-dir -u usr1 ``` -#Plugin variables +## Plugin variables - **gssapi-keytab-path** (Unix only) - Path to the server keytab file - **gssapi-principal-name** - name of the service principal. - **gssapi-mech-name** (Windows only) - Name of the SSPI package used by server. Can be either 'Kerberos' or 'Negotiate'. @@ -111,7 +111,7 @@ mysql --plugin-dir=/path/to/plugin-dir -u usr1 to allow non-domain environment (e.g if server does not run in domain environment). -#Implementation +## Implementation Overview of the protocol between client and server From 90bbeafb7a2c848153aa09b7004ac23a8be68905 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 20 Feb 2024 13:20:12 +0200 Subject: [PATCH 07/20] Get rid of error when running mariadb-install-db with --log-bin This removes the error: "Failed to load slave replication state from table mysql.gtid_slave_pos: 1017: Can't find file: './mysql/' (errno: 2 "No such file or directory") --- sql/mysqld.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f03e5780ad9..25630aae76f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4710,9 +4710,9 @@ static int init_server_components() proc_info_hook= set_thd_stage_info; /* - Print source revision hash, as one of the first lines, if not the - first in error log, for troubleshooting and debugging purposes - */ + Print source revision hash, as one of the first lines, if not the + first in error log, for troubleshooting and debugging purposes + */ if (!opt_help) sql_print_information("Starting MariaDB %s source revision %s as process %lu", server_version, SOURCE_REVISION, (ulong) getpid()); @@ -4740,6 +4740,19 @@ static int init_server_components() xid_cache_init(); + /* + Do not open binlong when doing bootstrap. + This ensures that rpl_load_gtid_slave_state() will not fail with an error + as the mysql schema does not yet exists. + This also ensures that we don't get an empty binlog file if the user has + log-bin in his config files. + */ + if (opt_bootstrap) + { + opt_bin_log= opt_bin_log_used= binlog_format_used= 0; + opt_log_slave_updates= 0; + } + /* need to configure logging before initializing storage engines */ if (!opt_bin_log_used && !WSREP_ON) { From 1bbbb66e4685ba3ab3cf9ed4e4b85a5a77c4c5d2 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 20 Feb 2024 13:48:20 +0200 Subject: [PATCH 08/20] Disable error messages in mysql-install-db for not writable log directory --- scripts/mysql_install_db.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/scripts/mysql_install_db.sh b/scripts/mysql_install_db.sh index 3bc4d63b7df..70ca9b0e0cb 100644 --- a/scripts/mysql_install_db.sh +++ b/scripts/mysql_install_db.sh @@ -537,6 +537,25 @@ else filter_cmd_line="cat" fi +# Disable log error if the user don't have right to write/create the file +# This is common when a user tries to install a personal mariadbd server and +# the global config in /etc is using --log-error. +# The server will internally change log-error to stderr to stderr if it cannot +# write the the log file. This code only disables the error message from a not +# writable log-error, which can be confusing. +if test -n "$log_error" +then + if test \( -e "$log_error" -a \! -w "$log_error" \) -o \( ! -e "$log_error" -a ! -w "`dirname "$log_error"`" \) + then + if test -n "$verbose" + then + echo "resetting log-error '$log_error' because no write access" + fi + log_error="" + args="$args --skip-log-error" + fi +fi + # Configure mysqld command line mysqld_bootstrap="${MYSQLD_BOOTSTRAP-$mysqld}" mysqld_install_cmd_line() From b04c857596722f892cf01cf931b33472ba1ca180 Mon Sep 17 00:00:00 2001 From: Brandon Nesterenko Date: Tue, 20 Feb 2024 08:16:15 -0700 Subject: [PATCH 09/20] MDEV-33500: rpl.rpl_parallel_sbm can fail on slow machines, e.g. MSAN/Valgrind builders In an addition to test rpl.rpl_parallel_sbm added by MDEV-32265, the test uses sleep statements alone to test Seconds_Behind_Master with delayed replication. On slow running machines, the test can pass the intended MASTER_DELAY duration and Seconds_Behind_Master can become 0, when the test expects the transaction to still be actively in a delaying state. This can be consistently reproduced by adding a sleep statement before the call to --let = query_get_value(SHOW SLAVE STATUS, Seconds_Behind_Master, 1) to sleep past the delay end point. This patch fixes this by locking the table which the delayed transaction targets so Second_Behind_Master cannot be updated before the test reads it for validation. --- mysql-test/suite/rpl/r/rpl_parallel_sbm.result | 7 +++++++ mysql-test/suite/rpl/t/rpl_parallel_sbm.test | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_parallel_sbm.result b/mysql-test/suite/rpl/r/rpl_parallel_sbm.result index 7990a663f04..e349353ac59 100644 --- a/mysql-test/suite/rpl/r/rpl_parallel_sbm.result +++ b/mysql-test/suite/rpl/r/rpl_parallel_sbm.result @@ -27,12 +27,19 @@ connection slave; # delaying a transaction; then when the reciprocal START SLAVE occurs, # if the event is still to be delayed, SBM should resume accordingly include/stop_slave.inc +# Lock t1 on slave to ensure the event can't finish (and thereby update +# Seconds_Behind_Master) so slow running servers don't accidentally +# catch up to the master before checking SBM. +connection server_2; +LOCK TABLES t1 WRITE; include/start_slave.inc connection slave; # Waiting for replica to resume the delay for the transaction # Sleeping 1s to increment SBM # Ensuring Seconds_Behind_Master increases after sleeping.. # ..done +connection server_2; +UNLOCK TABLES; include/sync_with_master_gtid.inc # # Pt 2) If the worker threads have not entered an idle state, ensure diff --git a/mysql-test/suite/rpl/t/rpl_parallel_sbm.test b/mysql-test/suite/rpl/t/rpl_parallel_sbm.test index 58c0db15e47..9c502ff6cb9 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_sbm.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_sbm.test @@ -67,6 +67,13 @@ if (`SELECT $sbm_trx1_arrive > ($seconds_since_idling + 1)`) --echo # if the event is still to be delayed, SBM should resume accordingly --source include/stop_slave.inc + +--echo # Lock t1 on slave to ensure the event can't finish (and thereby update +--echo # Seconds_Behind_Master) so slow running servers don't accidentally +--echo # catch up to the master before checking SBM. +--connection server_2 +LOCK TABLES t1 WRITE; + --source include/start_slave.inc --connection slave @@ -86,6 +93,9 @@ if (`SELECT $sbm_trx1_after_1s_sleep <= $sbm_trx1_arrive`) } --echo # ..done +--connection server_2 +UNLOCK TABLES; + --source include/sync_with_master_gtid.inc --echo # From 0f0da95db09a0e6046b9436efda307e1ffd715f5 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 21 Feb 2024 14:17:34 +1100 Subject: [PATCH 10/20] MDEV-33493 Spider: Make a symlink result file a normal file --- .../r/udf_mysql_func_early_init_file.result | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) mode change 120000 => 100644 storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result diff --git a/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result b/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result deleted file mode 120000 index 045ddc4372c..00000000000 --- a/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result +++ /dev/null @@ -1 +0,0 @@ -udf_mysql_func_early.result \ No newline at end of file diff --git a/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result b/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result new file mode 100644 index 00000000000..b84f60a67fb --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/udf_mysql_func_early_init_file.result @@ -0,0 +1,43 @@ +# +# Test that udf created by inserting into mysql_func works as expected +# +CREATE SERVER s_1 FOREIGN DATA WRAPPER mysql OPTIONS ( +HOST 'localhost', +DATABASE 'auto_test_local', +USER 'root', +PASSWORD '', +SOCKET '$MASTER_1_MYSOCK' + ); +CREATE SERVER s_2_1 FOREIGN DATA WRAPPER mysql OPTIONS ( +HOST 'localhost', +DATABASE 'auto_test_remote', +USER 'root', +PASSWORD '', +SOCKET '$CHILD2_1_MYSOCK' + ); +connect master_1, localhost, root, , , $MASTER_1_MYPORT, $MASTER_1_MYSOCK; +connect child2_1, localhost, root, , , $CHILD2_1_MYPORT, $CHILD2_1_MYSOCK; +connection child2_1; +CREATE DATABASE auto_test_remote; +USE auto_test_remote; +CREATE TABLE tbl_a ( +a INT +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +insert into tbl_a values (42); +connection master_1; +CREATE DATABASE auto_test_local; +USE auto_test_local; +CREATE TABLE tbl_a ( +a INT +) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_a", srv "s_2_1"'; +create temporary table results (a int); +SELECT SPIDER_DIRECT_SQL('select * from tbl_a', 'results', 'srv "s_2_1", database "auto_test_remote"'); +SPIDER_DIRECT_SQL('select * from tbl_a', 'results', 'srv "s_2_1", database "auto_test_remote"') +1 +select * from results; +a +42 +connection master_1; +DROP DATABASE IF EXISTS auto_test_local; +connection child2_1; +DROP DATABASE IF EXISTS auto_test_remote; From d57c44f62635d6afe026345c11b13f543741e83e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Feb 2024 22:05:00 -0800 Subject: [PATCH 11/20] MDEV-31277 Wrong result on 2-nd execution of PS to select from view using derived As a result of this bug the second execution of the prepared statement created for select from materialized view could return a wrong result set if - the specification of the view used a left join - an inner table the left join was a mergeable derived table - the derived table contained a constant column. The problem appeared because the flag 'maybe-null' of the wrapper Item_direct_view_ref constructed for the constant field of the mergeable derived table was not set to 'true' on the second execution of the prepared statement. The patch always sets this flag properly when calling the function Item_direct_view_ref::set_null_ref-table(). The latter is invoked in Item_direct_view_ref constructor if it is created for some reference of a constant column belonging to a mergeable derived table. Approved by Oleksandr Byelkin --- mysql-test/main/derived_view.result | 32 +++++++++++++++++++++++++ mysql-test/main/derived_view.test | 36 +++++++++++++++++++++++++++++ mysql-test/main/join_outer.test | 12 ---------- sql/item.h | 2 ++ 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/mysql-test/main/derived_view.result b/mysql-test/main/derived_view.result index c2fe217ee97..64113cbe403 100644 --- a/mysql-test/main/derived_view.result +++ b/mysql-test/main/derived_view.result @@ -4250,3 +4250,35 @@ dim1 dim2 dim3 p SUM(p) 100 10 1 2 371 DROP VIEW v; # End of 10.4 tests +# +# MDEV-31277: 2-nd execution of PS to select from materialized view +# specified as left join whose inner table is mergeable +# derived containing a constant column +# +create table t1 ( +Election int(10) unsigned NOT NULL +) engine=MyISAM; +insert into t1 (Election) values (1), (4); +create table t2 ( +VoteID int(10), +ElectionID int(10), +UserID int(10) +); +insert into t2 (ElectionID, UserID) values (2, 30), (3, 30); +create view v1 as select * from t1 +left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T +on T.ElectionID = t1.Election +limit 9; +prepare stmt1 from "select * from v1"; +execute stmt1; +Election Voted ElectionID +1 NULL NULL +4 NULL NULL +execute stmt1; +Election Voted ElectionID +1 NULL NULL +4 NULL NULL +deallocate prepare stmt1; +drop view v1; +drop table t1, t2; +# End of 10.5 tests diff --git a/mysql-test/main/derived_view.test b/mysql-test/main/derived_view.test index f9ab0443bc0..9747f1df61f 100644 --- a/mysql-test/main/derived_view.test +++ b/mysql-test/main/derived_view.test @@ -2832,3 +2832,39 @@ SELECT d.*, SUM(p) FROM demo d; DROP VIEW v; --echo # End of 10.4 tests + +--echo # +--echo # MDEV-31277: 2-nd execution of PS to select from materialized view +--echo # specified as left join whose inner table is mergeable +--echo # derived containing a constant column +--echo # + +create table t1 ( + Election int(10) unsigned NOT NULL +) engine=MyISAM; + +insert into t1 (Election) values (1), (4); + +create table t2 ( + VoteID int(10), + ElectionID int(10), + UserID int(10) +); + +insert into t2 (ElectionID, UserID) values (2, 30), (3, 30); +create view v1 as select * from t1 + left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T + on T.ElectionID = t1.Election +limit 9; + +prepare stmt1 from "select * from v1"; + +execute stmt1; +execute stmt1; + +deallocate prepare stmt1; + +drop view v1; +drop table t1, t2; + +--echo # End of 10.5 tests diff --git a/mysql-test/main/join_outer.test b/mysql-test/main/join_outer.test index 857a9ced41b..da3c82109d8 100644 --- a/mysql-test/main/join_outer.test +++ b/mysql-test/main/join_outer.test @@ -2372,11 +2372,8 @@ create view v1 as select * from t1 left join ( select 'Y' AS Voted, ElectionID from t2 ) AS T on T.ElectionID = t1.Election limit 9; -#enable after fix MDEV-31277 ---disable_ps2_protocol # limit X causes merge algorithm select as opposed to temp table select * from v1; ---enable_ps2_protocol drop table t1, t2; drop view v1; @@ -2391,10 +2388,7 @@ create view v10 as select *, 'U' as u from t10 left join (select 'Y' as y, t20.b create table t30 (c int); insert into t30 values (1),(3); create view v20 as select * from t30 left join (select 'X' as x, v10.u, v10.y, v10.b from v10) dt2 on t30.c=dt2.b limit 6; -#check after fix MDEV-31277 ---disable_ps2_protocol select * from v20 limit 9; ---enable_ps2_protocol drop view v10, v20; drop table t10, t20, t30; @@ -2408,8 +2402,6 @@ insert into t3 values (3),(1); create table t1 (a int); insert into t1 values (1),(2),(7),(1); -#check after fix MDEV-31277 ---disable_ps2_protocol select * from ( select * from @@ -2422,7 +2414,6 @@ select * from on dt1.a=dt2.b limit 9 ) dt; ---enable_ps2_protocol ## Same as dt3 above create view v3(x,c) as select * from (select 'X' as x, t3.c from t3) dt3; @@ -2436,10 +2427,7 @@ create view v0(y,b,x,c) as select * from v2 left join v3 on v2.b=v3.c; # Same as above select statement create view v1 as select 'Z' as z, t1.a, v0.* from t1 left join v0 on t1.a=v0.b limit 9; -#check after fix MDEV-31277 ---disable_ps2_protocol select * from v1; ---enable_ps2_protocol set statement join_cache_level=0 for select * from v1; diff --git a/sql/item.h b/sql/item.h index c08671d46bb..f5c9ed2a7ab 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5876,6 +5876,8 @@ class Item_direct_view_ref :public Item_direct_ref if (!view->is_inner_table_of_outer_join() || !(null_ref_table= view->get_real_join_table())) null_ref_table= NO_NULL_TABLE; + if (null_ref_table && null_ref_table != NO_NULL_TABLE) + maybe_null= true; } bool check_null_ref() From e63311c2cf9c4cf9071429370a1567ce4c6f369b Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 21 Feb 2024 11:41:50 +0400 Subject: [PATCH 12/20] MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type Functions extracting non-negative datetime components: - YEAR(dt), EXTRACT(YEAR FROM dt) - QUARTER(td), EXTRACT(QUARTER FROM dt) - MONTH(dt), EXTRACT(MONTH FROM dt) - WEEK(dt), EXTRACT(WEEK FROM dt) - HOUR(dt), - MINUTE(dt), - SECOND(dt), - MICROSECOND(dt), - DAYOFYEAR(dt) - EXTRACT(YEAR_MONTH FROM dt) did not set their max_length properly, so in the DECIMAL context they created a too small DECIMAL column, which led to the 'Out of range value' error. The problem is that most of these functions historically returned the signed INT data type. There were two simple ways to fix these functions: 1. Add +1 to max_length. But this would also change their size in the string context and create too long VARCHAR columns, with +1 excessive size. 2. Preserve max_length, but change the data type from INT to INT UNSIGNED. But this would break backward compatibility. Also, using UNSIGNED is generally not desirable, it's better to stay with signed when possible. This fix implements another solution, which it makes all these functions work well in all contexts: int, decimal, string. Fix details: - Adding a new special class Type_handler_long_ge0 - the data type handler for expressions which: * should look like normal signed INT * but which known not to return negative values Expressions handled by Type_handler_long_ge0 store in Item::max_length only the number of digits, without adding +1 for the sign. - Fixing Item_extract to use Type_handler_long_ge0 for non-negative datetime components: YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK - Adding a new abstract class Item_long_ge0_func, for functions returning non-negative datetime components. Item_long_ge0_func uses Type_handler_long_ge0 as the type handler. The class hierarchy now looks as follows: Item_long_ge0_func Item_long_func_date_field Item_func_to_days Item_func_dayofmonth Item_func_dayofyear Item_func_quarter Item_func_year Item_long_func_time_field Item_func_hour Item_func_minute Item_func_second Item_func_microsecond - Cleanup: EXTRACT(QUARTER FROM dt) created an excessive VARCHAR column in string context. Changing its length from 2 to 1. --- mysql-test/main/func_extract.result | 882 +++++++++++++++++++++++++ mysql-test/main/func_extract.test | 251 +++++++ mysql-test/main/func_time.result | 20 +- mysql-test/main/ps_2myisam.result | 4 +- mysql-test/main/ps_3innodb.result | 4 +- mysql-test/main/ps_4heap.result | 4 +- mysql-test/main/ps_5merge.result | 8 +- mysql-test/suite/maria/ps_maria.result | 4 +- sql/item_func.cc | 32 +- sql/item_func.h | 27 + sql/item_sum.cc | 15 + sql/item_sum.h | 1 + sql/item_timefunc.cc | 2 +- sql/item_timefunc.h | 33 +- sql/sql_type.cc | 91 +++ sql/sql_type.h | 33 + 16 files changed, 1373 insertions(+), 38 deletions(-) diff --git a/mysql-test/main/func_extract.result b/mysql-test/main/func_extract.result index bebb8c717f6..dc71f6ae27a 100644 --- a/mysql-test/main/func_extract.result +++ b/mysql-test/main/func_extract.result @@ -590,3 +590,885 @@ Warning 1292 Truncated incorrect time value: '01:02:03/' Warning 1292 Truncated incorrect time value: '01:02:03/' Warning 1292 Truncated incorrect INTERVAL DAY TO SECOND value: '01:02:03/' DROP TABLE t1; +# +# Start of 10.5 tests +# +# +# MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type +# +CREATE FUNCTION select01() RETURNS TEXT RETURN 'SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?'; +CREATE FUNCTION select02() RETURNS TEXT RETURN 'SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)'; +CREATE TABLE t1 (a DATETIME(6)); +INSERT INTO t1 VALUES ('2001-12-31 10:20:30.999999'); +CREATE FUNCTION params(expr TEXT, count INT) RETURNS TEXT +BEGIN +RETURN CONCAT(expr, REPEAT(CONCAT(', ', expr), count-1)); +END; +$$ +CREATE PROCEDURE show_drop() +BEGIN +SELECT TABLE_NAME, COLUMN_TYPE, COLUMN_NAME +FROM INFORMATION_SCHEMA.COLUMNS +WHERE TABLE_SCHEMA='test' + AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm', +'t1e_ps','t1f_ps','t2e_ps','t2f_ps') +ORDER BY LEFT(TABLE_NAME, 2), ORDINAL_POSITION, TABLE_NAME; +FOR rec IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES +WHERE TABLE_SCHEMA='test' + AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm', +'t1e_ps','t1f_ps','t2e_ps','t2f_ps')) +DO +EXECUTE IMMEDIATE CONCAT('DROP TABLE ', rec.TABLE_NAME); +END FOR; +END; +$$ +CREATE PROCEDURE p1(unit VARCHAR(32)) +BEGIN +DECLARE do_extract BOOL DEFAULT unit NOT IN('DAYOFYEAR'); +DECLARE query01 TEXT DEFAULT +CONCAT('CREATE TABLE t2 AS ', select01(), ' FROM t1'); +DECLARE query02 TEXT DEFAULT +CONCAT('CREATE TABLE t2 AS ', select02(), ' FROM t1'); +IF (do_extract) +THEN +EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)')); +EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)')); +END IF; +EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1f_nm'),'?', CONCAT(unit,'(a)')); +EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2f_nm'),'?', CONCAT(unit,'(a)')); +END; +$$ + + +# EXTRACT(YEAR FROM expr) and YEAR(expr) are equivalent +CALL p1('YEAR'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(YEAR FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), YEAR(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(5) EXTRACT(YEAR FROM a) +t1e_ps int(5) ? +t1f_nm int(5) YEAR(a) +t1f_ps int(5) ? +t1e_nm int(4) unsigned CAST(EXTRACT(YEAR FROM a) AS UNSIGNED) +t1e_ps int(4) unsigned CAST(? AS UNSIGNED) +t1f_nm int(4) unsigned CAST(YEAR(a) AS UNSIGNED) +t1f_ps int(4) unsigned CAST(? AS UNSIGNED) +t1e_nm int(5) CAST(EXTRACT(YEAR FROM a) AS SIGNED) +t1e_ps int(5) CAST(? AS SIGNED) +t1f_nm int(5) CAST(YEAR(a) AS SIGNED) +t1f_ps int(5) CAST(? AS SIGNED) +t1e_nm int(5) ABS(EXTRACT(YEAR FROM a)) +t1e_ps int(5) ABS(?) +t1f_nm int(5) ABS(YEAR(a)) +t1f_ps int(5) ABS(?) +t1e_nm int(5) ROUND(EXTRACT(YEAR FROM a)) +t1e_ps int(5) ROUND(?) +t1f_nm int(5) ROUND(YEAR(a)) +t1f_ps int(5) ROUND(?) +t1e_nm int(5) -EXTRACT(YEAR FROM a) +t1e_ps int(5) -? +t1f_nm int(5) -YEAR(a) +t1f_ps int(5) -? +t1e_nm int(6) ROUND(EXTRACT(YEAR FROM a),-1) +t1e_ps int(6) ROUND(?,-1) +t1f_nm int(6) ROUND(YEAR(a),-1) +t1f_ps int(6) ROUND(?,-1) +t1e_nm int(6) EXTRACT(YEAR FROM a)+0 +t1e_ps int(6) ?+0 +t1f_nm int(6) YEAR(a)+0 +t1f_ps int(6) ?+0 +t1e_nm decimal(6,1) EXTRACT(YEAR FROM a)+0.0 +t1e_ps decimal(6,1) ?+0.0 +t1f_nm decimal(6,1) YEAR(a)+0.0 +t1f_ps decimal(6,1) ?+0.0 +t1e_nm varchar(4) CONCAT(EXTRACT(YEAR FROM a)) +t1e_ps varchar(4) CONCAT(?) +t1f_nm varchar(4) CONCAT(YEAR(a)) +t1f_ps varchar(4) CONCAT(?) +t1e_nm int(5) LEAST(EXTRACT(YEAR FROM a),EXTRACT(YEAR FROM a)) +t1e_ps int(5) LEAST(?,?) +t1f_nm int(5) LEAST(YEAR(a),YEAR(a)) +t1f_ps int(5) LEAST(?,?) +t1e_nm int(5) COALESCE(EXTRACT(YEAR FROM a)) +t1e_ps int(5) COALESCE(?) +t1f_nm int(5) COALESCE(YEAR(a)) +t1f_ps int(5) COALESCE(?) +t1e_nm int(5) COALESCE(EXTRACT(YEAR FROM a),CAST(1 AS SIGNED)) +t1e_ps int(5) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(5) COALESCE(YEAR(a),CAST(1 AS SIGNED)) +t1f_ps int(5) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(4,0) COALESCE(EXTRACT(YEAR FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(4,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(4,0) COALESCE(YEAR(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(4,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(5) @a:=EXTRACT(YEAR FROM a) +t1e_ps int(5) @a:=? +t1f_nm int(5) @a:=YEAR(a) +t1f_ps int(5) @a:=? +t2e_nm decimal(8,4) AVG(EXTRACT(YEAR FROM a)) +t2e_ps decimal(8,4) AVG(?) +t2f_nm decimal(8,4) AVG(YEAR(a)) +t2f_ps decimal(8,4) AVG(?) +t2e_nm bigint(5) MIN(EXTRACT(YEAR FROM a)) +t2e_ps bigint(5) MIN(?) +t2f_nm bigint(5) MIN(YEAR(a)) +t2f_ps bigint(5) MIN(?) +t2e_nm bigint(5) MAX(EXTRACT(YEAR FROM a)) +t2e_ps bigint(5) MAX(?) +t2f_nm bigint(5) MAX(YEAR(a)) +t2f_ps bigint(5) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(YEAR FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(YEAR(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(QUARTER FROM expr) and QUARTER(expr) are equavalent +CALL p1('QUARTER'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(QUARTER FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'), QUARTER(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(2) EXTRACT(QUARTER FROM a) +t1e_ps int(2) ? +t1f_nm int(2) QUARTER(a) +t1f_ps int(2) ? +t1e_nm int(1) unsigned CAST(EXTRACT(QUARTER FROM a) AS UNSIGNED) +t1e_ps int(1) unsigned CAST(? AS UNSIGNED) +t1f_nm int(1) unsigned CAST(QUARTER(a) AS UNSIGNED) +t1f_ps int(1) unsigned CAST(? AS UNSIGNED) +t1e_nm int(2) CAST(EXTRACT(QUARTER FROM a) AS SIGNED) +t1e_ps int(2) CAST(? AS SIGNED) +t1f_nm int(2) CAST(QUARTER(a) AS SIGNED) +t1f_ps int(2) CAST(? AS SIGNED) +t1e_nm int(2) ABS(EXTRACT(QUARTER FROM a)) +t1e_ps int(2) ABS(?) +t1f_nm int(2) ABS(QUARTER(a)) +t1f_ps int(2) ABS(?) +t1e_nm int(2) ROUND(EXTRACT(QUARTER FROM a)) +t1e_ps int(2) ROUND(?) +t1f_nm int(2) ROUND(QUARTER(a)) +t1f_ps int(2) ROUND(?) +t1e_nm int(2) -EXTRACT(QUARTER FROM a) +t1e_ps int(2) -? +t1f_nm int(2) -QUARTER(a) +t1f_ps int(2) -? +t1e_nm int(3) ROUND(EXTRACT(QUARTER FROM a),-1) +t1e_ps int(3) ROUND(?,-1) +t1f_nm int(3) ROUND(QUARTER(a),-1) +t1f_ps int(3) ROUND(?,-1) +t1e_nm int(3) EXTRACT(QUARTER FROM a)+0 +t1e_ps int(3) ?+0 +t1f_nm int(3) QUARTER(a)+0 +t1f_ps int(3) ?+0 +t1e_nm decimal(3,1) EXTRACT(QUARTER FROM a)+0.0 +t1e_ps decimal(3,1) ?+0.0 +t1f_nm decimal(3,1) QUARTER(a)+0.0 +t1f_ps decimal(3,1) ?+0.0 +t1e_nm varchar(1) CONCAT(EXTRACT(QUARTER FROM a)) +t1e_ps varchar(1) CONCAT(?) +t1f_nm varchar(1) CONCAT(QUARTER(a)) +t1f_ps varchar(1) CONCAT(?) +t1e_nm int(2) LEAST(EXTRACT(QUARTER FROM a),EXTRACT(QUARTER FROM a)) +t1e_ps int(2) LEAST(?,?) +t1f_nm int(2) LEAST(QUARTER(a),QUARTER(a)) +t1f_ps int(2) LEAST(?,?) +t1e_nm int(2) COALESCE(EXTRACT(QUARTER FROM a)) +t1e_ps int(2) COALESCE(?) +t1f_nm int(2) COALESCE(QUARTER(a)) +t1f_ps int(2) COALESCE(?) +t1e_nm int(2) COALESCE(EXTRACT(QUARTER FROM a),CAST(1 AS SIGNED)) +t1e_ps int(2) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(2) COALESCE(QUARTER(a),CAST(1 AS SIGNED)) +t1f_ps int(2) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(1,0) COALESCE(EXTRACT(QUARTER FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(1,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(1,0) COALESCE(QUARTER(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(1,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(2) @a:=EXTRACT(QUARTER FROM a) +t1e_ps int(2) @a:=? +t1f_nm int(2) @a:=QUARTER(a) +t1f_ps int(2) @a:=? +t2e_nm decimal(5,4) AVG(EXTRACT(QUARTER FROM a)) +t2e_ps decimal(5,4) AVG(?) +t2f_nm decimal(5,4) AVG(QUARTER(a)) +t2f_ps decimal(5,4) AVG(?) +t2e_nm bigint(2) MIN(EXTRACT(QUARTER FROM a)) +t2e_ps bigint(2) MIN(?) +t2f_nm bigint(2) MIN(QUARTER(a)) +t2f_ps bigint(2) MIN(?) +t2e_nm bigint(2) MAX(EXTRACT(QUARTER FROM a)) +t2e_ps bigint(2) MAX(?) +t2f_nm bigint(2) MAX(QUARTER(a)) +t2f_ps bigint(2) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(QUARTER FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(QUARTER(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(MONTH FROM expr) and MONTH(expr) are equavalent +CALL p1('MONTH'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MONTH FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'), MONTH(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(MONTH FROM a) +t1e_ps int(3) ? +t1f_nm int(3) MONTH(a) +t1f_ps int(3) ? +t1e_nm int(2) unsigned CAST(EXTRACT(MONTH FROM a) AS UNSIGNED) +t1e_ps int(2) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(MONTH(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(MONTH FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(MONTH(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(MONTH FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(MONTH(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(MONTH FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(MONTH(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(3) -EXTRACT(MONTH FROM a) +t1e_ps int(3) -? +t1f_nm int(3) -MONTH(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(MONTH FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(MONTH(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(MONTH FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) MONTH(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(MONTH FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) MONTH(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(2) CONCAT(EXTRACT(MONTH FROM a)) +t1e_ps varchar(2) CONCAT(?) +t1f_nm varchar(2) CONCAT(MONTH(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(MONTH FROM a),EXTRACT(MONTH FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(MONTH(a),MONTH(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(MONTH FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(MONTH(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(MONTH FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(MONTH(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(MONTH FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(MONTH(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(MONTH FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=MONTH(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(MONTH FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(MONTH(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(MONTH FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(MONTH(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(MONTH FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(MONTH(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MONTH FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(MONTH(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(WEEK FROM expr) and WEEK(expr) are equavalent +CALL p1('WEEK'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(WEEK FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'), WEEK(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(WEEK FROM a) +t1e_ps int(3) ? +t1f_nm int(3) WEEK(a) +t1f_ps int(3) ? +t1e_nm int(2) unsigned CAST(EXTRACT(WEEK FROM a) AS UNSIGNED) +t1e_ps int(2) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(WEEK(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(WEEK FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(WEEK(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(WEEK FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(WEEK(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(WEEK FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(WEEK(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(3) -EXTRACT(WEEK FROM a) +t1e_ps int(3) -? +t1f_nm int(3) -WEEK(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(WEEK FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(WEEK(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(WEEK FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) WEEK(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(WEEK FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) WEEK(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(2) CONCAT(EXTRACT(WEEK FROM a)) +t1e_ps varchar(2) CONCAT(?) +t1f_nm varchar(2) CONCAT(WEEK(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(WEEK FROM a),EXTRACT(WEEK FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(WEEK(a),WEEK(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(WEEK FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(WEEK(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(WEEK FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(WEEK(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(WEEK FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(WEEK(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(WEEK FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=WEEK(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(WEEK FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(WEEK(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(WEEK FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(WEEK(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(WEEK FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(WEEK(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(WEEK FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(WEEK(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(DAY FROM expr) returns hours/24 and includes the sign for TIME +# DAY(expr) returns the DD part of CAST(expr AS DATETIME) +CALL p1('DAY'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(DAY FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'), DAY(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(DAY FROM a) +t1e_ps int(3) ? +t1f_nm int(3) DAY(a) +t1f_ps int(3) ? +t1e_nm bigint(20) unsigned CAST(EXTRACT(DAY FROM a) AS UNSIGNED) +t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(DAY(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(DAY FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(DAY(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(DAY FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(DAY(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(DAY FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(DAY(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(4) -EXTRACT(DAY FROM a) +t1e_ps int(4) -? +t1f_nm int(3) -DAY(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(DAY FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(DAY(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(DAY FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) DAY(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(DAY FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) DAY(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(3) CONCAT(EXTRACT(DAY FROM a)) +t1e_ps varchar(3) CONCAT(?) +t1f_nm varchar(2) CONCAT(DAY(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(DAY FROM a),EXTRACT(DAY FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(DAY(a),DAY(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(DAY FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(DAY(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(DAY FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(DAY(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(DAY FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(DAY(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(DAY FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=DAY(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(DAY FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(DAY(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(DAY FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(DAY(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(DAY FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(DAY(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(DAY FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(DAY(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(HOUR FROM expr) returns hours%24 and includes the sign for TIME +# HOUR(expr) returns the hh part of CAST(expr AS DATETIME) +CALL p1('HOUR'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(HOUR FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'), HOUR(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(HOUR FROM a) +t1e_ps int(3) ? +t1f_nm int(3) HOUR(a) +t1f_ps int(3) ? +t1e_nm bigint(20) unsigned CAST(EXTRACT(HOUR FROM a) AS UNSIGNED) +t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(HOUR(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(HOUR FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(HOUR(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(HOUR FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(HOUR(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(HOUR FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(HOUR(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(4) -EXTRACT(HOUR FROM a) +t1e_ps int(4) -? +t1f_nm int(3) -HOUR(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(HOUR FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(HOUR(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(HOUR FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) HOUR(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(HOUR FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) HOUR(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(3) CONCAT(EXTRACT(HOUR FROM a)) +t1e_ps varchar(3) CONCAT(?) +t1f_nm varchar(2) CONCAT(HOUR(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(HOUR FROM a),EXTRACT(HOUR FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(HOUR(a),HOUR(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(HOUR FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(HOUR(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(HOUR FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(HOUR(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(HOUR FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(HOUR(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(HOUR FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=HOUR(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(HOUR FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(HOUR(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(HOUR FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(HOUR(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(HOUR FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(HOUR(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(HOUR FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(HOUR(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(MINUTE FROM expr) includes the sign for TIME +# MINUTE(expr) returns the absolute value +CALL p1('MINUTE'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MINUTE FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'), MINUTE(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(MINUTE FROM a) +t1e_ps int(3) ? +t1f_nm int(3) MINUTE(a) +t1f_ps int(3) ? +t1e_nm bigint(20) unsigned CAST(EXTRACT(MINUTE FROM a) AS UNSIGNED) +t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(MINUTE(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(MINUTE FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(MINUTE(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(MINUTE FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(MINUTE(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(MINUTE FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(MINUTE(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(4) -EXTRACT(MINUTE FROM a) +t1e_ps int(4) -? +t1f_nm int(3) -MINUTE(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(MINUTE FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(MINUTE(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(MINUTE FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) MINUTE(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(MINUTE FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) MINUTE(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(3) CONCAT(EXTRACT(MINUTE FROM a)) +t1e_ps varchar(3) CONCAT(?) +t1f_nm varchar(2) CONCAT(MINUTE(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(MINUTE FROM a),EXTRACT(MINUTE FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(MINUTE(a),MINUTE(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(MINUTE FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(MINUTE(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(MINUTE FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(MINUTE(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(MINUTE FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(MINUTE(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(MINUTE FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=MINUTE(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(MINUTE FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(MINUTE(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(MINUTE FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(MINUTE(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(MINUTE FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(MINUTE(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MINUTE FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(MINUTE(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(SECONDS FROM expr) includes the sign for TIME +# SECONDS(expr) returns the absolute value +CALL p1('SECOND'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(SECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), SECOND(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(3) EXTRACT(SECOND FROM a) +t1e_ps int(3) ? +t1f_nm int(3) SECOND(a) +t1f_ps int(3) ? +t1e_nm bigint(20) unsigned CAST(EXTRACT(SECOND FROM a) AS UNSIGNED) +t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED) +t1f_nm int(2) unsigned CAST(SECOND(a) AS UNSIGNED) +t1f_ps int(2) unsigned CAST(? AS UNSIGNED) +t1e_nm int(3) CAST(EXTRACT(SECOND FROM a) AS SIGNED) +t1e_ps int(3) CAST(? AS SIGNED) +t1f_nm int(3) CAST(SECOND(a) AS SIGNED) +t1f_ps int(3) CAST(? AS SIGNED) +t1e_nm int(3) ABS(EXTRACT(SECOND FROM a)) +t1e_ps int(3) ABS(?) +t1f_nm int(3) ABS(SECOND(a)) +t1f_ps int(3) ABS(?) +t1e_nm int(3) ROUND(EXTRACT(SECOND FROM a)) +t1e_ps int(3) ROUND(?) +t1f_nm int(3) ROUND(SECOND(a)) +t1f_ps int(3) ROUND(?) +t1e_nm int(4) -EXTRACT(SECOND FROM a) +t1e_ps int(4) -? +t1f_nm int(3) -SECOND(a) +t1f_ps int(3) -? +t1e_nm int(4) ROUND(EXTRACT(SECOND FROM a),-1) +t1e_ps int(4) ROUND(?,-1) +t1f_nm int(4) ROUND(SECOND(a),-1) +t1f_ps int(4) ROUND(?,-1) +t1e_nm int(4) EXTRACT(SECOND FROM a)+0 +t1e_ps int(4) ?+0 +t1f_nm int(4) SECOND(a)+0 +t1f_ps int(4) ?+0 +t1e_nm decimal(4,1) EXTRACT(SECOND FROM a)+0.0 +t1e_ps decimal(4,1) ?+0.0 +t1f_nm decimal(4,1) SECOND(a)+0.0 +t1f_ps decimal(4,1) ?+0.0 +t1e_nm varchar(3) CONCAT(EXTRACT(SECOND FROM a)) +t1e_ps varchar(3) CONCAT(?) +t1f_nm varchar(2) CONCAT(SECOND(a)) +t1f_ps varchar(2) CONCAT(?) +t1e_nm int(3) LEAST(EXTRACT(SECOND FROM a),EXTRACT(SECOND FROM a)) +t1e_ps int(3) LEAST(?,?) +t1f_nm int(3) LEAST(SECOND(a),SECOND(a)) +t1f_ps int(3) LEAST(?,?) +t1e_nm int(3) COALESCE(EXTRACT(SECOND FROM a)) +t1e_ps int(3) COALESCE(?) +t1f_nm int(3) COALESCE(SECOND(a)) +t1f_ps int(3) COALESCE(?) +t1e_nm int(3) COALESCE(EXTRACT(SECOND FROM a),CAST(1 AS SIGNED)) +t1e_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(3) COALESCE(SECOND(a),CAST(1 AS SIGNED)) +t1f_ps int(3) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(2,0) COALESCE(EXTRACT(SECOND FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(2,0) COALESCE(SECOND(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(2,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(3) @a:=EXTRACT(SECOND FROM a) +t1e_ps int(3) @a:=? +t1f_nm int(3) @a:=SECOND(a) +t1f_ps int(3) @a:=? +t2e_nm decimal(6,4) AVG(EXTRACT(SECOND FROM a)) +t2e_ps decimal(6,4) AVG(?) +t2f_nm decimal(6,4) AVG(SECOND(a)) +t2f_ps decimal(6,4) AVG(?) +t2e_nm bigint(3) MIN(EXTRACT(SECOND FROM a)) +t2e_ps bigint(3) MIN(?) +t2f_nm bigint(3) MIN(SECOND(a)) +t2f_ps bigint(3) MIN(?) +t2e_nm bigint(3) MAX(EXTRACT(SECOND FROM a)) +t2e_ps bigint(3) MAX(?) +t2f_nm bigint(3) MAX(SECOND(a)) +t2f_ps bigint(3) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(SECOND FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(SECOND(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# EXTRACT(MICROSECONDS FROM expr) includes the sign for TIME +# MICROSECONDS(expr) returns the absolute value +CALL p1('MICROSECOND'); +EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'), EXTRACT(MICROSECOND FROM TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'), MICROSECOND(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1e_nm int(7) EXTRACT(MICROSECOND FROM a) +t1e_ps int(7) ? +t1f_nm int(7) MICROSECOND(a) +t1f_ps int(7) ? +t1e_nm bigint(20) unsigned CAST(EXTRACT(MICROSECOND FROM a) AS UNSIGNED) +t1e_ps bigint(20) unsigned CAST(? AS UNSIGNED) +t1f_nm int(6) unsigned CAST(MICROSECOND(a) AS UNSIGNED) +t1f_ps int(6) unsigned CAST(? AS UNSIGNED) +t1e_nm int(7) CAST(EXTRACT(MICROSECOND FROM a) AS SIGNED) +t1e_ps int(7) CAST(? AS SIGNED) +t1f_nm int(7) CAST(MICROSECOND(a) AS SIGNED) +t1f_ps int(7) CAST(? AS SIGNED) +t1e_nm int(7) ABS(EXTRACT(MICROSECOND FROM a)) +t1e_ps int(7) ABS(?) +t1f_nm int(7) ABS(MICROSECOND(a)) +t1f_ps int(7) ABS(?) +t1e_nm int(7) ROUND(EXTRACT(MICROSECOND FROM a)) +t1e_ps int(7) ROUND(?) +t1f_nm int(7) ROUND(MICROSECOND(a)) +t1f_ps int(7) ROUND(?) +t1e_nm int(8) -EXTRACT(MICROSECOND FROM a) +t1e_ps int(8) -? +t1f_nm int(7) -MICROSECOND(a) +t1f_ps int(7) -? +t1e_nm int(8) ROUND(EXTRACT(MICROSECOND FROM a),-1) +t1e_ps int(8) ROUND(?,-1) +t1f_nm int(8) ROUND(MICROSECOND(a),-1) +t1f_ps int(8) ROUND(?,-1) +t1e_nm int(8) EXTRACT(MICROSECOND FROM a)+0 +t1e_ps int(8) ?+0 +t1f_nm int(8) MICROSECOND(a)+0 +t1f_ps int(8) ?+0 +t1e_nm decimal(8,1) EXTRACT(MICROSECOND FROM a)+0.0 +t1e_ps decimal(8,1) ?+0.0 +t1f_nm decimal(8,1) MICROSECOND(a)+0.0 +t1f_ps decimal(8,1) ?+0.0 +t1e_nm varchar(7) CONCAT(EXTRACT(MICROSECOND FROM a)) +t1e_ps varchar(7) CONCAT(?) +t1f_nm varchar(6) CONCAT(MICROSECOND(a)) +t1f_ps varchar(6) CONCAT(?) +t1e_nm int(7) LEAST(EXTRACT(MICROSECOND FROM a),EXTRACT(MICROSECOND FROM a)) +t1e_ps int(7) LEAST(?,?) +t1f_nm int(7) LEAST(MICROSECOND(a),MICROSECOND(a)) +t1f_ps int(7) LEAST(?,?) +t1e_nm int(7) COALESCE(EXTRACT(MICROSECOND FROM a)) +t1e_ps int(7) COALESCE(?) +t1f_nm int(7) COALESCE(MICROSECOND(a)) +t1f_ps int(7) COALESCE(?) +t1e_nm int(7) COALESCE(EXTRACT(MICROSECOND FROM a),CAST(1 AS SIGNED)) +t1e_ps int(7) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm int(7) COALESCE(MICROSECOND(a),CAST(1 AS SIGNED)) +t1f_ps int(7) COALESCE(?,CAST(1 AS SIGNED)) +t1e_nm decimal(6,0) COALESCE(EXTRACT(MICROSECOND FROM a),CAST(1 AS UNSIGNED)) +t1e_ps decimal(6,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm decimal(6,0) COALESCE(MICROSECOND(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(6,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1e_nm int(7) @a:=EXTRACT(MICROSECOND FROM a) +t1e_ps int(7) @a:=? +t1f_nm int(7) @a:=MICROSECOND(a) +t1f_ps int(7) @a:=? +t2e_nm decimal(10,4) AVG(EXTRACT(MICROSECOND FROM a)) +t2e_ps decimal(10,4) AVG(?) +t2f_nm decimal(10,4) AVG(MICROSECOND(a)) +t2f_ps decimal(10,4) AVG(?) +t2e_nm bigint(7) MIN(EXTRACT(MICROSECOND FROM a)) +t2e_ps bigint(7) MIN(?) +t2f_nm bigint(7) MIN(MICROSECOND(a)) +t2f_ps bigint(7) MIN(?) +t2e_nm bigint(7) MAX(EXTRACT(MICROSECOND FROM a)) +t2e_ps bigint(7) MAX(?) +t2f_nm bigint(7) MAX(MICROSECOND(a)) +t2f_ps bigint(7) MAX(?) +t2e_nm mediumtext GROUP_CONCAT(EXTRACT(MICROSECOND FROM a)) +t2e_ps mediumtext GROUP_CONCAT(?) +t2f_nm mediumtext GROUP_CONCAT(MICROSECOND(a)) +t2f_ps mediumtext GROUP_CONCAT(?) + + +# DAYOFYEAR +CALL p1('DAYOFYEAR'); +EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?' USING DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'); +EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?)' USING DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'), DAYOFYEAR(TIMESTAMP'2001-12-13 10:20:30.999999'); +CALL show_drop; +TABLE_NAME COLUMN_TYPE COLUMN_NAME +t1f_nm int(4) DAYOFYEAR(a) +t1f_ps int(4) ? +t1f_nm int(3) unsigned CAST(DAYOFYEAR(a) AS UNSIGNED) +t1f_ps int(3) unsigned CAST(? AS UNSIGNED) +t1f_nm int(4) CAST(DAYOFYEAR(a) AS SIGNED) +t1f_ps int(4) CAST(? AS SIGNED) +t1f_nm int(4) ABS(DAYOFYEAR(a)) +t1f_ps int(4) ABS(?) +t1f_nm int(4) ROUND(DAYOFYEAR(a)) +t1f_ps int(4) ROUND(?) +t1f_nm int(4) -DAYOFYEAR(a) +t1f_ps int(4) -? +t1f_nm int(5) ROUND(DAYOFYEAR(a),-1) +t1f_ps int(5) ROUND(?,-1) +t1f_nm int(5) DAYOFYEAR(a)+0 +t1f_ps int(5) ?+0 +t1f_nm decimal(5,1) DAYOFYEAR(a)+0.0 +t1f_ps decimal(5,1) ?+0.0 +t1f_nm varchar(3) CONCAT(DAYOFYEAR(a)) +t1f_ps varchar(3) CONCAT(?) +t1f_nm int(4) LEAST(DAYOFYEAR(a),DAYOFYEAR(a)) +t1f_ps int(4) LEAST(?,?) +t1f_nm int(4) COALESCE(DAYOFYEAR(a)) +t1f_ps int(4) COALESCE(?) +t1f_nm int(4) COALESCE(DAYOFYEAR(a),CAST(1 AS SIGNED)) +t1f_ps int(4) COALESCE(?,CAST(1 AS SIGNED)) +t1f_nm decimal(3,0) COALESCE(DAYOFYEAR(a),CAST(1 AS UNSIGNED)) +t1f_ps decimal(3,0) COALESCE(?,CAST(1 AS UNSIGNED)) +t1f_nm int(4) @a:=DAYOFYEAR(a) +t1f_ps int(4) @a:=? +t2f_nm decimal(7,4) AVG(DAYOFYEAR(a)) +t2f_ps decimal(7,4) AVG(?) +t2f_nm bigint(4) MIN(DAYOFYEAR(a)) +t2f_ps bigint(4) MIN(?) +t2f_nm bigint(4) MAX(DAYOFYEAR(a)) +t2f_ps bigint(4) MAX(?) +t2f_nm mediumtext GROUP_CONCAT(DAYOFYEAR(a)) +t2f_ps mediumtext GROUP_CONCAT(?) +DROP TABLE t1; +DROP PROCEDURE p1; +DROP PROCEDURE show_drop; +DROP FUNCTION params; +DROP FUNCTION select01; +DROP FUNCTION select02; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/func_extract.test b/mysql-test/main/func_extract.test index 97920f1872f..dd808443f58 100644 --- a/mysql-test/main/func_extract.test +++ b/mysql-test/main/func_extract.test @@ -263,3 +263,254 @@ SELECT FROM t1; DROP TABLE t1; --enable_view_protocol + + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type +--echo # + +let select01=SELECT ?, CAST(? AS UNSIGNED), CAST(? AS SIGNED), ABS(?), ROUND(?), -?, ROUND(?,-1), ?+0, ?+0.0, CONCAT(?), LEAST(?,?), COALESCE(?), COALESCE(?,CAST(1 AS SIGNED)), COALESCE(?,CAST(1 AS UNSIGNED)), @a:=?; +let pcount01=16; +let select02=SELECT AVG(?), MIN(?), MAX(?), GROUP_CONCAT(?); +let pcount02=4; +let ts=TIMESTAMP'2001-12-13 10:20:30.999999'; + +eval CREATE FUNCTION select01() RETURNS TEXT RETURN '$select01'; +eval CREATE FUNCTION select02() RETURNS TEXT RETURN '$select02'; + +CREATE TABLE t1 (a DATETIME(6)); +INSERT INTO t1 VALUES ('2001-12-31 10:20:30.999999'); + +DELIMITER $$; +CREATE FUNCTION params(expr TEXT, count INT) RETURNS TEXT +BEGIN + RETURN CONCAT(expr, REPEAT(CONCAT(', ', expr), count-1)); +END; +$$ +CREATE PROCEDURE show_drop() +BEGIN + SELECT TABLE_NAME, COLUMN_TYPE, COLUMN_NAME + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_SCHEMA='test' + AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm', + 't1e_ps','t1f_ps','t2e_ps','t2f_ps') + ORDER BY LEFT(TABLE_NAME, 2), ORDINAL_POSITION, TABLE_NAME; + + FOR rec IN (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_SCHEMA='test' + AND TABLE_NAME IN ('t1e_nm','t2e_nm','t1f_nm','t2f_nm', + 't1e_ps','t1f_ps','t2e_ps','t2f_ps')) + DO + EXECUTE IMMEDIATE CONCAT('DROP TABLE ', rec.TABLE_NAME); + END FOR; +END; +$$ +CREATE PROCEDURE p1(unit VARCHAR(32)) +BEGIN + DECLARE do_extract BOOL DEFAULT unit NOT IN('DAYOFYEAR'); + + DECLARE query01 TEXT DEFAULT + CONCAT('CREATE TABLE t2 AS ', select01(), ' FROM t1'); + + DECLARE query02 TEXT DEFAULT + CONCAT('CREATE TABLE t2 AS ', select02(), ' FROM t1'); + + IF (do_extract) + THEN + EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)')); + EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2e_nm'),'?', CONCAT('EXTRACT(',unit,' FROM a)')); + END IF; + EXECUTE IMMEDIATE REPLACE(REPLACE(query01,'t2','t1f_nm'),'?', CONCAT(unit,'(a)')); + EXECUTE IMMEDIATE REPLACE(REPLACE(query02,'t2','t2f_nm'),'?', CONCAT(unit,'(a)')); +END; +$$ +DELIMITER ;$$ + + +--echo +--echo +--echo # EXTRACT(YEAR FROM expr) and YEAR(expr) are equivalent + +CALL p1('YEAR'); +let extr=EXTRACT(YEAR FROM $ts); +let func=YEAR($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + + +--echo +--echo +--echo # EXTRACT(QUARTER FROM expr) and QUARTER(expr) are equavalent + +CALL p1('QUARTER'); +let extr=EXTRACT(QUARTER FROM $ts); +let func=QUARTER($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(MONTH FROM expr) and MONTH(expr) are equavalent + +CALL p1('MONTH'); +let extr=EXTRACT(MONTH FROM $ts); +let func=MONTH($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(WEEK FROM expr) and WEEK(expr) are equavalent + +CALL p1('WEEK'); +let extr=EXTRACT(WEEK FROM $ts); +let func=WEEK($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(DAY FROM expr) returns hours/24 and includes the sign for TIME +--echo # DAY(expr) returns the DD part of CAST(expr AS DATETIME) + +CALL p1('DAY'); +let extr=EXTRACT(DAY FROM $ts); +let func=DAY($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(HOUR FROM expr) returns hours%24 and includes the sign for TIME +--echo # HOUR(expr) returns the hh part of CAST(expr AS DATETIME) + +CALL p1('HOUR'); +let extr=EXTRACT(HOUR FROM $ts); +let func=HOUR($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(MINUTE FROM expr) includes the sign for TIME +--echo # MINUTE(expr) returns the absolute value + +CALL p1('MINUTE'); +let extr=EXTRACT(MINUTE FROM $ts); +let func=MINUTE($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(SECONDS FROM expr) includes the sign for TIME +--echo # SECONDS(expr) returns the absolute value + +CALL p1('SECOND'); +let extr=EXTRACT(SECOND FROM $ts); +let func=SECOND($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # EXTRACT(MICROSECONDS FROM expr) includes the sign for TIME +--echo # MICROSECONDS(expr) returns the absolute value + +CALL p1('MICROSECOND'); +let extr=EXTRACT(MICROSECOND FROM $ts); +let func=MICROSECOND($ts); +let extr01=`SELECT params("$extr", $pcount01) AS p`; +let func01=`SELECT params("$func", $pcount01) AS p`; +let extr02=`SELECT params("$extr", $pcount02) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1e_ps AS $select01' USING $extr01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2e_ps AS $select02' USING $extr02; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + +--echo +--echo +--echo # DAYOFYEAR + +CALL p1('DAYOFYEAR'); +let func=DAYOFYEAR($ts); +let func01=`SELECT params("$func", $pcount01) AS p`; +let func02=`SELECT params("$func", $pcount02) AS p`; +eval EXECUTE IMMEDIATE 'CREATE TABLE t1f_ps AS $select01' USING $func01; +eval EXECUTE IMMEDIATE 'CREATE TABLE t2f_ps AS $select02' USING $func02; +CALL show_drop; + + +DROP TABLE t1; +DROP PROCEDURE p1; +DROP PROCEDURE show_drop; +DROP FUNCTION params; + +DROP FUNCTION select01; +DROP FUNCTION select02; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/mysql-test/main/func_time.result b/mysql-test/main/func_time.result index e7ff2001711..0f807a691b3 100644 --- a/mysql-test/main/func_time.result +++ b/mysql-test/main/func_time.result @@ -3142,7 +3142,7 @@ Catalog Database Table Table_alias Column Column_alias Type Length Max length Is def test t1 t1 a a 12 26 26 Y 128 6 63 def EXTRACT(YEAR FROM a) 3 4 4 Y 32896 0 63 def EXTRACT(YEAR_MONTH FROM a) 3 6 6 Y 32896 0 63 -def EXTRACT(QUARTER FROM a) 3 2 1 Y 32896 0 63 +def EXTRACT(QUARTER FROM a) 3 1 1 Y 32896 0 63 def EXTRACT(MONTH FROM a) 3 2 2 Y 32896 0 63 def EXTRACT(WEEK FROM a) 3 2 2 Y 32896 0 63 def EXTRACT(DAY FROM a) 3 3 2 Y 32896 0 63 @@ -3230,11 +3230,11 @@ SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( `a` datetime(6) DEFAULT NULL, - `EXTRACT(YEAR FROM a)` int(4) DEFAULT NULL, - `EXTRACT(YEAR_MONTH FROM a)` int(6) DEFAULT NULL, + `EXTRACT(YEAR FROM a)` int(5) DEFAULT NULL, + `EXTRACT(YEAR_MONTH FROM a)` int(7) DEFAULT NULL, `EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL, - `EXTRACT(MONTH FROM a)` int(2) DEFAULT NULL, - `EXTRACT(WEEK FROM a)` int(2) DEFAULT NULL, + `EXTRACT(MONTH FROM a)` int(3) DEFAULT NULL, + `EXTRACT(WEEK FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL, `EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL, @@ -3281,7 +3281,7 @@ Catalog Database Table Table_alias Column Column_alias Type Length Max length Is def test t1 t1 a a 11 17 17 Y 128 6 63 def EXTRACT(YEAR FROM a) 3 4 1 Y 32896 0 63 def EXTRACT(YEAR_MONTH FROM a) 3 6 1 Y 32896 0 63 -def EXTRACT(QUARTER FROM a) 3 2 1 Y 32896 0 63 +def EXTRACT(QUARTER FROM a) 3 1 1 Y 32896 0 63 def EXTRACT(MONTH FROM a) 3 2 1 Y 32896 0 63 def EXTRACT(WEEK FROM a) 3 2 9 Y 32896 0 63 def EXTRACT(DAY FROM a) 3 3 3 Y 32896 0 63 @@ -3411,11 +3411,11 @@ SHOW CREATE TABLE t2; Table Create Table t2 CREATE TABLE `t2` ( `a` time(6) DEFAULT NULL, - `EXTRACT(YEAR FROM a)` int(4) DEFAULT NULL, - `EXTRACT(YEAR_MONTH FROM a)` int(6) DEFAULT NULL, + `EXTRACT(YEAR FROM a)` int(5) DEFAULT NULL, + `EXTRACT(YEAR_MONTH FROM a)` int(7) DEFAULT NULL, `EXTRACT(QUARTER FROM a)` int(2) DEFAULT NULL, - `EXTRACT(MONTH FROM a)` int(2) DEFAULT NULL, - `EXTRACT(WEEK FROM a)` int(2) DEFAULT NULL, + `EXTRACT(MONTH FROM a)` int(3) DEFAULT NULL, + `EXTRACT(WEEK FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY FROM a)` int(3) DEFAULT NULL, `EXTRACT(DAY_HOUR FROM a)` int(5) DEFAULT NULL, `EXTRACT(DAY_MINUTE FROM a)` int(7) DEFAULT NULL, diff --git a/mysql-test/main/ps_2myisam.result b/mysql-test/main/ps_2myisam.result index 256665ce4cb..ec365498833 100644 --- a/mysql-test/main/ps_2myisam.result +++ b/mysql-test/main/ps_2myisam.result @@ -1798,7 +1798,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -1828,7 +1828,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 diff --git a/mysql-test/main/ps_3innodb.result b/mysql-test/main/ps_3innodb.result index 675587e020a..1c98a59cff5 100644 --- a/mysql-test/main/ps_3innodb.result +++ b/mysql-test/main/ps_3innodb.result @@ -1781,7 +1781,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -1811,7 +1811,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 diff --git a/mysql-test/main/ps_4heap.result b/mysql-test/main/ps_4heap.result index dcde7613bfe..db182536e93 100644 --- a/mysql-test/main/ps_4heap.result +++ b/mysql-test/main/ps_4heap.result @@ -1782,7 +1782,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -1812,7 +1812,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 diff --git a/mysql-test/main/ps_5merge.result b/mysql-test/main/ps_5merge.result index c9d33dbb1ae..963a3a60359 100644 --- a/mysql-test/main/ps_5merge.result +++ b/mysql-test/main/ps_5merge.result @@ -1719,7 +1719,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -1749,7 +1749,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 @@ -5087,7 +5087,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -5117,7 +5117,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 diff --git a/mysql-test/suite/maria/ps_maria.result b/mysql-test/suite/maria/ps_maria.result index 5c128a32dd1..3f806c43dbd 100644 --- a/mysql-test/suite/maria/ps_maria.result +++ b/mysql-test/suite/maria/ps_maria.result @@ -1798,7 +1798,7 @@ t5 CREATE TABLE `t5` ( `param09` longtext DEFAULT NULL, `const10` bigint(17) DEFAULT NULL, `param10` bigint(20) DEFAULT NULL, - `const11` int(4) DEFAULT NULL, + `const11` int(5) DEFAULT NULL, `param11` bigint(20) DEFAULT NULL, `const12` binary(0) DEFAULT NULL, `param12` bigint(20) DEFAULT NULL, @@ -1828,7 +1828,7 @@ def test t5 t5 const09 const09 12 19 19 Y 128 0 63 def test t5 t5 param09 param09 252 4294967295 19 Y 16 0 8 def test t5 t5 const10 const10 8 17 9 Y 32768 0 63 def test t5 t5 param10 param10 8 20 9 Y 32768 0 63 -def test t5 t5 const11 const11 3 4 4 Y 32768 0 63 +def test t5 t5 const11 const11 3 5 4 Y 32768 0 63 def test t5 t5 param11 param11 8 20 4 Y 32768 0 63 def test t5 t5 const12 const12 254 0 0 Y 128 0 63 def test t5 t5 param12 param12 8 20 0 Y 32768 0 63 diff --git a/sql/item_func.cc b/sql/item_func.cc index b3f12cec3af..f6fa613cba6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1918,6 +1918,18 @@ void Item_func_abs::fix_length_and_dec_int() set_handler(type_handler_long_or_longlong()); } +void Item_func_abs::fix_length_and_dec_sint_ge0() +{ + /* + We're converting slong_ge0 to slong/slonglong. + Add one character for the sign into max_length. + */ + max_length= args[0]->decimal_precision() + 1/*sign*/; + DBUG_ASSERT(!args[0]->unsigned_flag); + unsigned_flag= false; + set_handler(type_handler_long_or_longlong()); +} + void Item_func_abs::fix_length_and_dec_double() { @@ -2594,6 +2606,22 @@ void Item_func_round::fix_arg_int(const Type_handler *preferred, } +void Item_func_round::fix_arg_slong_ge0() +{ + DBUG_ASSERT(!args[0]->unsigned_flag); + DBUG_ASSERT(args[0]->decimals == 0); + Type_std_attributes::set(args[0]); + /* + We're converting the data type from slong_ge0 to slong/slonglong. + Add one character for the sign, + to change max_length notation from "max_length digits" to + "max_length-1 digits and the sign". + */ + max_length+= 1/*sign*/ + test_if_length_can_increase(); + set_handler(type_handler_long_or_longlong()); +} + + void Item_func_round::fix_arg_hex_hybrid() { DBUG_ASSERT(args[0]->decimals == 0); @@ -4801,7 +4829,9 @@ Item_func_set_user_var::fix_length_and_dec() if (args[0]->collation.derivation == DERIVATION_NUMERIC) { collation.set(DERIVATION_NUMERIC); - fix_length_and_charset(args[0]->max_char_length(), &my_charset_numeric); + uint sign_length= args[0]->type_handler() == &type_handler_slong_ge0 ? 1: 0; + fix_length_and_charset(args[0]->max_char_length() + sign_length, + &my_charset_numeric); } else { diff --git a/sql/item_func.h b/sql/item_func.h index b205d457f1d..0f4f8928847 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1239,6 +1239,24 @@ public: }; +class Item_long_ge0_func: public Item_int_func +{ +public: + Item_long_ge0_func(THD *thd): Item_int_func(thd) { } + Item_long_ge0_func(THD *thd, Item *a): Item_int_func(thd, a) {} + Item_long_ge0_func(THD *thd, Item *a, Item *b): Item_int_func(thd, a, b) {} + Item_long_ge0_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {} + Item_long_ge0_func(THD *thd, List &list): Item_int_func(thd, list) { } + Item_long_ge0_func(THD *thd, Item_long_ge0_func *item) :Item_int_func(thd, item) {} + const Type_handler *type_handler() const + { + DBUG_ASSERT(!unsigned_flag); + return &type_handler_slong_ge0; + } + bool fix_length_and_dec() { max_length= 10; return FALSE; } +}; + + class Item_func_hash: public Item_int_func { public: @@ -1362,6 +1380,13 @@ public: { fix_char_length(MAX_BIGINT_WIDTH); } + void fix_length_and_dec_sint_ge0() + { + uint32 digits= args[0]->decimal_precision(); + DBUG_ASSERT(digits > 0); + DBUG_ASSERT(digits <= MY_INT64_NUM_DECIMAL_DIGITS); + fix_char_length(digits + (unsigned_flag ? 0 : 1/*sign*/)); + } void fix_length_and_dec_generic() { uint32 char_length= MY_MIN(args[0]->max_char_length(), @@ -1723,6 +1748,7 @@ public: my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "abs"; } void fix_length_and_dec_int(); + void fix_length_and_dec_sint_ge0(); void fix_length_and_dec_double(); void fix_length_and_dec_decimal(); bool fix_length_and_dec(); @@ -1981,6 +2007,7 @@ public: void fix_arg_int(const Type_handler *preferred, const Type_std_attributes *preferred_attributes, bool use_decimal_on_length_increase); + void fix_arg_slong_ge0(); void fix_arg_hex_hybrid(); void fix_arg_double(); void fix_arg_time(); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index c3ff95ccf33..99e1d622bf8 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1205,6 +1205,21 @@ bool Item_sum_hybrid::fix_length_and_dec_numeric(const Type_handler *handler) } +bool Item_sum_hybrid::fix_length_and_dec_sint_ge0() +{ + // We don't have Item_field's of "ge0" type handlers. + DBUG_ASSERT(args[0]->real_item()->type() != FIELD_ITEM); + Type_std_attributes::set(args[0]); + /* + We're converting from e.g. slong_ge0 to slonglong + and need to add one extra character for the sign. + */ + max_length++; + set_handler(&type_handler_slonglong); + return false; +} + + /** MAX(str_field) converts ENUM/SET to CHAR, and preserve all other types for Fields. diff --git a/sql/item_sum.h b/sql/item_sum.h index 9f858725598..847407c6c0c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1115,6 +1115,7 @@ public: { return Type_handler_hybrid_field_type::type_handler(); } bool fix_length_and_dec_generic(); bool fix_length_and_dec_numeric(const Type_handler *h); + bool fix_length_and_dec_sint_ge0(); bool fix_length_and_dec_string(); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 1672eee3443..a58f3593463 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2142,7 +2142,7 @@ bool Item_extract::fix_length_and_dec() switch (int_type) { case INTERVAL_YEAR: set_date_length(4); break; // YYYY case INTERVAL_YEAR_MONTH: set_date_length(6); break; // YYYYMM - case INTERVAL_QUARTER: set_date_length(2); break; // 1..4 + case INTERVAL_QUARTER: set_date_length(1); break; // 1..4 case INTERVAL_MONTH: set_date_length(2); break; // MM case INTERVAL_WEEK: set_date_length(2); break; // 0..52 case INTERVAL_DAY: set_day_length(daylen); break; // DD diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a910b2cb723..d8012c74e05 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -30,23 +30,23 @@ bool get_interval_value(THD *thd, Item *args, interval_type int_type, INTERVAL *interval); -class Item_long_func_date_field: public Item_long_func +class Item_long_func_date_field: public Item_long_ge0_func { bool check_arguments() const { return args[0]->check_type_can_return_date(func_name()); } public: Item_long_func_date_field(THD *thd, Item *a) - :Item_long_func(thd, a) { } + :Item_long_ge0_func(thd, a) { } }; -class Item_long_func_time_field: public Item_long_func +class Item_long_func_time_field: public Item_long_ge0_func { bool check_arguments() const { return args[0]->check_type_can_return_time(func_name()); } public: Item_long_func_time_field(THD *thd, Item *a) - :Item_long_func(thd, a) { } + :Item_long_ge0_func(thd, a) { } }; @@ -166,10 +166,10 @@ public: }; -class Item_func_month :public Item_long_func +class Item_func_month :public Item_long_ge0_func { public: - Item_func_month(THD *thd, Item *a): Item_long_func(thd, a) + Item_func_month(THD *thd, Item *a): Item_long_ge0_func(thd, a) { } longlong val_int(); const char *func_name() const { return "month"; } @@ -333,7 +333,7 @@ public: }; -class Item_func_week :public Item_long_func +class Item_func_week :public Item_long_ge0_func { bool check_arguments() const { @@ -341,8 +341,8 @@ class Item_func_week :public Item_long_func (arg_count > 1 && args[1]->check_type_can_return_int(func_name())); } public: - Item_func_week(THD *thd, Item *a): Item_long_func(thd, a) {} - Item_func_week(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {} + Item_func_week(THD *thd, Item *a): Item_long_ge0_func(thd, a) {} + Item_func_week(THD *thd, Item *a, Item *b): Item_long_ge0_func(thd, a, b) {} longlong val_int(); const char *func_name() const { return "week"; } bool fix_length_and_dec() @@ -969,12 +969,17 @@ class Item_extract :public Item_int_func, void set_date_length(uint32 length) { /* - Although DATE components (e.g. YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK) - cannot have a sign, we should probably still add +1, - because all around the code we assume that max_length is sign inclusive. - Another options is to set unsigned_flag to "true". + DATE components (e.g. YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK) + return non-negative values but historically EXTRACT for date + components always returned the signed int data type. + So do equivalent functions YEAR(), QUARTER(), MONTH(), WEEK(). + Let's set the data type to "signed int, but not negative", + so "this" produces better data types in VARCHAR and DECIMAL context + by using the fact that all of the max_length characters are spent + for digits (non of them are spent for the sign). */ - set_handler(handler_by_length(max_length= length, 10)); // QQ: see above + set_handler(&type_handler_slong_ge0); + fix_char_length(length); m_date_mode= date_mode_t(0); } void set_day_length(uint32 length) diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 77931b6cf16..9ede9e2582d 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -41,6 +41,7 @@ Named_type_handler type_handler_bool("boolean"); Named_type_handler type_handler_stiny("tinyint"); Named_type_handler type_handler_sshort("smallint"); Named_type_handler type_handler_slong("int"); +Named_type_handler type_handler_slong_ge0("int"); Named_type_handler type_handler_sint24("mediumint"); Named_type_handler type_handler_slonglong("bigint"); Named_type_handler type_handler_utiny("tiny unsigned"); @@ -4629,6 +4630,10 @@ bool Type_handler_general_purpose_int:: bool unsigned_flag= items[0]->unsigned_flag; for (uint i= 1; i < nitems; i++) { + /* + TODO: avoid creating DECIMAL for a mix of ulong and slong_ge0. + It's too late for 10.5. Let's do it in a higher version. + */ if (unsigned_flag != items[i]->unsigned_flag) { // Convert a mixture of signed and unsigned int to decimal @@ -4638,6 +4643,21 @@ bool Type_handler_general_purpose_int:: } } func->aggregate_attributes_int(items, nitems); + for (uint i= 0; i < nitems; i++) + { + if (items[i]->type_handler() == &type_handler_slong_ge0) + { + /* + A slong_ge0 argument found. + We need to add an extra character for the sign. + TODO: rewrite aggregate_attributes_int() to find + the maximum decimal_precision() instead of the maximum max_length. + This change is too late for 10.5, so let's do it in a higher version. + */ + uint digits_and_sign= items[i]->decimal_precision() + 1; + set_if_bigger(func->max_length, digits_and_sign); + } + } handler->set_handler(func->unsigned_flag ? handler->type_handler()->type_handler_unsigned() : handler->type_handler()->type_handler_signed()); @@ -4931,6 +4951,13 @@ bool Type_handler_real_result:: /*************************************************************************/ +bool Type_handler_long_ge0:: + Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const +{ + return func->fix_length_and_dec_sint_ge0(); +} + + bool Type_handler_int_result:: Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const { @@ -6373,6 +6400,14 @@ bool Type_handler_int_result:: } +bool Type_handler_long_ge0:: + Item_func_round_fix_length_and_dec(Item_func_round *item) const +{ + item->fix_arg_slong_ge0(); + return false; +} + + bool Type_handler_year:: Item_func_round_fix_length_and_dec(Item_func_round *item) const { @@ -6594,6 +6629,14 @@ bool Type_handler_int_result:: } +bool Type_handler_long_ge0:: + Item_func_abs_fix_length_and_dec(Item_func_abs *item) const +{ + item->fix_length_and_dec_sint_ge0(); + return false; +} + + bool Type_handler_real_result:: Item_func_abs_fix_length_and_dec(Item_func_abs *item) const { @@ -6704,6 +6747,22 @@ bool Type_handler:: } +bool Type_handler_long_ge0:: + Item_func_signed_fix_length_and_dec(Item_func_signed *item) const +{ + item->fix_length_and_dec_sint_ge0(); + return false; +} + + +bool Type_handler_long_ge0:: + Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const +{ + item->fix_length_and_dec_sint_ge0(); + return false; +} + + bool Type_handler_string_result:: Item_func_signed_fix_length_and_dec(Item_func_signed *item) const { @@ -7189,6 +7248,18 @@ uint Type_handler_int_result::Item_decimal_precision(const Item *item) const return MY_MIN(prec, DECIMAL_MAX_PRECISION); } +uint Type_handler_long_ge0::Item_decimal_precision(const Item *item) const +{ + DBUG_ASSERT(item->max_length); + DBUG_ASSERT(!item->decimals); + /* + Unlinke in Type_handler_long, Type_handler_long_ge does + not reserve one character for the sign. All max_length + characters are digits. + */ + return MY_MIN(item->max_length, DECIMAL_MAX_PRECISION); +} + uint Type_handler_time_common::Item_decimal_precision(const Item *item) const { return 7 + MY_MIN(item->decimals, TIME_SECOND_PART_DIGITS); @@ -8190,6 +8261,26 @@ Field *Type_handler_long:: } +Field *Type_handler_long_ge0:: + make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &rec, const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const +{ + /* + We're converting signed long_ge0 to signed long. + So add one character for the sign. + */ + return new (mem_root) + Field_long(rec.ptr(), (uint32) attr->length + 1/*sign*/, + rec.null_ptr(), rec.null_bit(), + attr->unireg_check, name, + f_is_zerofill(attr->pack_flag) != 0, + f_is_dec(attr->pack_flag) == 0); +} + + Field *Type_handler_longlong:: make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, const LEX_CSTRING *name, diff --git a/sql/sql_type.h b/sql/sql_type.h index c8c92e56253..62bb8945b5b 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -5758,6 +5758,38 @@ public: }; +/* + The expression of this type reports itself as signed, + however it's known not to return negative values. + Items of this data type count only digits in Item::max_length, + without adding +1 for the sign. This allows expressions + of this type convert nicely to VARCHAR and DECIMAL. + For example, YEAR(now()) is: + - VARCHAR(4) in a string context + - DECIMAL(4,0) in a decimal context + - but INT(5) in an integer context +*/ +class Type_handler_long_ge0: public Type_handler_long +{ +public: + uint Item_decimal_precision(const Item *item) const override; + bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) + const override; + bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) + const override; + bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override; + bool Item_func_round_fix_length_and_dec(Item_func_round *) const override; + bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override; + Field *make_table_field_from_def(TABLE_SHARE *share, + MEM_ROOT *mem_root, + const LEX_CSTRING *name, + const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const override; +}; + + class Type_handler_ulong: public Type_handler_long { public: @@ -7598,6 +7630,7 @@ extern MYSQL_PLUGIN_IMPORT Named_type_handler type_han extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_sshort; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_sint24; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slong; +extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slong_ge0; extern MYSQL_PLUGIN_IMPORT Named_type_handler type_handler_slonglong; extern Named_type_handler type_handler_utiny; From 8778a83eee9472fe15da185a188543595f262cda Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 22 Feb 2024 22:58:52 -0800 Subject: [PATCH 13/20] MDEV-31276 Wrong warnings on 2-nd execution of PS for query with GROUP_CONCAT If a query with GROUP_CONCAT is executed then the server reports a warning every time when the length of the result of this function exceeds the set value of the system variable group_concat_max_len. This bug led to the set of warnings from the second execution of the prepared statement that did not coincide with the one from the first execution if the executed query was a grouping query over a join of tables using GROUP_CONCAT function and join cache was not allowed to be employed. The descrepancy of the sets of warnings was due to lack of cleanup for Item_func_group_concat::row_count after execution of the query. Approved by Oleksandr Byelkin --- mysql-test/main/func_gconcat.result | 75 +++++++++++++++++++++++++++ mysql-test/main/func_gconcat.test | 40 ++++++++++++++ mysql-test/main/join_outer.test | 6 --- mysql-test/main/subselect_sj_mat.test | 9 ---- sql/item_sum.cc | 1 + 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/mysql-test/main/func_gconcat.result b/mysql-test/main/func_gconcat.result index fea25124941..7bc6441661b 100644 --- a/mysql-test/main/func_gconcat.result +++ b/mysql-test/main/func_gconcat.result @@ -1443,3 +1443,78 @@ drop table t1; # # End of 10.3 tests # +# +# MDEV-31276: Execution of PS from grouping query with join +# and GROUP_CONCAT set function +# +create table t1 (a int, b varchar(20)) engine=myisam; +create table t2 (a int, c varchar(20)) engine=myisam; +insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); +insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +insert into t2 values (1,"eeeeeee"),(2,"fffffff"); +set group_concat_max_len=5; +select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +explain select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using temporary; Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where; Using join buffer (flat, BNL join) +prepare stmt from "select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a"; +execute stmt; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +execute stmt; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +deallocate prepare stmt; +set join_cache_level=0; +select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +explain select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using filesort +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 Using where +prepare stmt from "select count(*), group_concat(t1.b,t2.c) +from t1 join t2 on t1.a=t2.a group by t1.a"; +execute stmt; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +execute stmt; +count(*) group_concat(t1.b,t2.c) +2 aaaaa +2 bbbbb +Warnings: +Warning 1260 Row 1 was cut by GROUP_CONCAT() +Warning 1260 Row 2 was cut by GROUP_CONCAT() +deallocate prepare stmt; +set join_cache_level=default; +set group_concat_max_len=default; +drop table t1,t2; +# End of 10.5 tests diff --git a/mysql-test/main/func_gconcat.test b/mysql-test/main/func_gconcat.test index cc5236a18be..2e09bddbb8b 100644 --- a/mysql-test/main/func_gconcat.test +++ b/mysql-test/main/func_gconcat.test @@ -1066,3 +1066,43 @@ drop table t1; --echo # --echo # End of 10.3 tests --echo # + +--echo # +--echo # MDEV-31276: Execution of PS from grouping query with join +--echo # and GROUP_CONCAT set function +--echo # + +create table t1 (a int, b varchar(20)) engine=myisam; +create table t2 (a int, c varchar(20)) engine=myisam; +insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); +insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); +insert into t2 values (1,"eeeeeee"),(2,"fffffff"); + +let $q= +select count(*), group_concat(t1.b,t2.c) + from t1 join t2 on t1.a=t2.a group by t1.a; + +set group_concat_max_len=5; + +eval $q; +eval explain $q; +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +set join_cache_level=0; + +eval $q; +eval explain $q; +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +set join_cache_level=default; +set group_concat_max_len=default; + +drop table t1,t2; + +--echo # End of 10.5 tests diff --git a/mysql-test/main/join_outer.test b/mysql-test/main/join_outer.test index da3c82109d8..83bb7fdeef3 100644 --- a/mysql-test/main/join_outer.test +++ b/mysql-test/main/join_outer.test @@ -685,15 +685,9 @@ create table t1 (a int, b varchar(20)); create table t2 (a int, c varchar(20)); insert into t1 values (1,"aaaaaaaaaa"),(2,"bbbbbbbbbb"); insert into t2 values (1,"cccccccccc"),(2,"dddddddddd"); -#Enable after fix MDEV-31276 ---disable_ps2_protocol select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by t1.a; ---enable_ps2_protocol select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; -#Enable after fix MDEV-31276 ---disable_ps2_protocol select group_concat(t1.b,t2.c) from t1 left join t2 using(a) group by a; ---enable_ps2_protocol select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by a; drop table t1, t2; set group_concat_max_len=default; diff --git a/mysql-test/main/subselect_sj_mat.test b/mysql-test/main/subselect_sj_mat.test index 000581d5758..6b343900dca 100644 --- a/mysql-test/main/subselect_sj_mat.test +++ b/mysql-test/main/subselect_sj_mat.test @@ -523,8 +523,6 @@ where a1 in (select substring(b1,1,512) from t2_512 where b1 > '0'); # group_concat with a blob argument - depends on # the variable group_concat_max_len, and # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB -#Check after fix MDEV-31276 ---disable_ps2_protocol explain extended select left(a1,7), left(a2,7) from t1_512 where a1 in (select group_concat(b1) from t2_512 group by b2); @@ -542,7 +540,6 @@ where a1 in (select group_concat(b1) from t2_512 group by b2); select left(a1,7), left(a2,7) from t1_512 where a1 in (select group_concat(b1) from t2_512 group by b2); ---enable_ps2_protocol drop table t1_512, t2_512, t3_512; @@ -608,8 +605,6 @@ where a1 in (select substring(b1,1,1024) from t2_1024 where b1 > '0'); # group_concat with a blob argument - depends on # the variable group_concat_max_len, and # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB -#Check after fix MDEV-31276 ---disable_ps2_protocol explain extended select left(a1,7), left(a2,7) from t1_1024 where a1 in (select group_concat(b1) from t2_1024 group by b2); @@ -627,7 +622,6 @@ where a1 in (select group_concat(b1) from t2_1024 group by b2); select left(a1,7), left(a2,7) from t1_1024 where a1 in (select group_concat(b1) from t2_1024 group by b2); ---enable_ps2_protocol drop table t1_1024, t2_1024, t3_1024; @@ -693,8 +687,6 @@ where a1 in (select substring(b1,1,1025) from t2_1025 where b1 > '0'); # group_concat with a blob argument - depends on # the variable group_concat_max_len, and # convert_blob_length == max_len*collation->mbmaxlen > CONVERT_IF_BIGGER_TO_BLOB -#Check after fix MDEV-31276 ---disable_ps2_protocol explain extended select left(a1,7), left(a2,7) from t1_1025 where a1 in (select group_concat(b1) from t2_1025 group by b2); @@ -712,7 +704,6 @@ where a1 in (select group_concat(b1) from t2_1025 group by b2); select left(a1,7), left(a2,7) from t1_1025 where a1 in (select group_concat(b1) from t2_1025 group by b2); ---enable_ps2_protocol drop table t1_1025, t2_1025, t3_1025; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 99e1d622bf8..7f39efe6c9a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -4056,6 +4056,7 @@ void Item_func_group_concat::cleanup() unique_filter= NULL; } } + row_count= 0; DBUG_ASSERT(tree == 0); } /* From 969669767ba4f4dcfadbcc73d14d0904ad3c6aca Mon Sep 17 00:00:00 2001 From: mariadb-DebarunBanerjee Date: Tue, 27 Feb 2024 17:59:20 +0530 Subject: [PATCH 14/20] MDEV-33011 mariabackup --backup: FATAL ERROR: ... Can't open datafile cool_down/t3 The root cause is the WAL logging of file operation when the actual operation fails afterwards. It creates a situation with a log entry for a operation that would always fail. I could simulate both the backup scenario error and Innodb recovery failure exploiting the weakness. We are following WAL for file rename operation and once logged the operation must eventually complete successfully, or it is a major catastrophe. Right now, we fail for rename and handle it as normal error and it is the problem. I created a patch to address RENAME operation to a non existing schema where the destination schema directory is missing. The patch checks for the missing schema before logging in an attempt to avoid the failure after WAL log is written/flushed. I also checked that the schema cannot be dropped or there cannot be any race with other rename to the same file. This is protected by the MDL lock in SQL today. The patch should this be a good improvement over the current situation and solves the issue at hand. --- mysql-test/suite/innodb/r/rename_table.result | 10 ++++- mysql-test/suite/innodb/t/rename_table.test | 9 ++++- .../mariabackup/rename_during_backup.result | 12 ++++++ .../mariabackup/rename_during_backup.test | 27 +++++++++++++ storage/innobase/fil/fil0fil.cc | 27 +++++++++---- storage/innobase/include/fil0fil.h | 38 +++++++++++++++++-- 6 files changed, 107 insertions(+), 16 deletions(-) diff --git a/mysql-test/suite/innodb/r/rename_table.result b/mysql-test/suite/innodb/r/rename_table.result index 23bb8c52d4a..ead04a91df4 100644 --- a/mysql-test/suite/innodb/r/rename_table.result +++ b/mysql-test/suite/innodb/r/rename_table.result @@ -20,9 +20,15 @@ path DROP DATABASE abc_def; # restart DROP DATABASE abc_def2; -call mtr.add_suppression("InnoDB: (Operating system error|The error means|Cannot rename file)"); +call mtr.add_suppression("InnoDB: Cannot rename '.*t1.ibd' to '.*non_existing_db.*' because the target schema directory doesn't exist"); CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES(100); RENAME TABLE t1 TO non_existing_db.t1; ERROR HY000: Error on rename of './test/t1' to './non_existing_db/t1' (errno: 168 "Unknown (generic) error from engine") -FOUND 1 /\[ERROR\] InnoDB: Cannot rename file '.*t1\.ibd' to '.*non_existing_db/ in mysqld.1.err +FOUND 1 /\[ERROR\] InnoDB: Cannot rename '.*t1\.ibd' to '.*non_existing_db/ in mysqld.1.err +SET GLOBAL innodb_fast_shutdown=2; +# restart +SELECT * FROM t1; +a +100 DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/rename_table.test b/mysql-test/suite/innodb/t/rename_table.test index 0191a94def2..f81deea0169 100644 --- a/mysql-test/suite/innodb/t/rename_table.test +++ b/mysql-test/suite/innodb/t/rename_table.test @@ -30,16 +30,21 @@ DROP DATABASE abc_def; DROP DATABASE abc_def2; -call mtr.add_suppression("InnoDB: (Operating system error|The error means|Cannot rename file)"); +call mtr.add_suppression("InnoDB: Cannot rename '.*t1.ibd' to '.*non_existing_db.*' because the target schema directory doesn't exist"); CREATE TABLE t1 (a INT) ENGINE=InnoDB; +INSERT INTO t1 VALUES(100); --replace_result "\\" "/" --error ER_ERROR_ON_RENAME RENAME TABLE t1 TO non_existing_db.t1; ---let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot rename file '.*t1\.ibd' to '.*non_existing_db +--let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot rename '.*t1\.ibd' to '.*non_existing_db let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; --source include/search_pattern_in_file.inc +SET GLOBAL innodb_fast_shutdown=2; +--source include/restart_mysqld.inc + +SELECT * FROM t1; # Cleanup DROP TABLE t1; diff --git a/mysql-test/suite/mariabackup/rename_during_backup.result b/mysql-test/suite/mariabackup/rename_during_backup.result index ba1dbec0e1b..c25b9d3a1b4 100644 --- a/mysql-test/suite/mariabackup/rename_during_backup.result +++ b/mysql-test/suite/mariabackup/rename_during_backup.result @@ -60,3 +60,15 @@ SELECT * from t6; i 5 DROP TABLE t6; +# +# MDEV-33011 mariabackup --backup: FATAL ERROR: ... Can't open datafile cool_down/t3 +# +# Simulate zero initialized page to defer tablespace load after rename log is found +SET @save_dbug = @@SESSION.debug_dbug; +SET DEBUG_DBUG="+d,checkpoint_after_file_create"; +CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); +# RENAME that fails after redo log entry is written and flushed +RENAME TABLE t1 TO non_existing_db.t1; +ERROR HY000: Error on rename of './test/t1' to './non_existing_db/t1' (errno: 168 "Unknown (generic) error from engine") +DROP TABLE t1; diff --git a/mysql-test/suite/mariabackup/rename_during_backup.test b/mysql-test/suite/mariabackup/rename_during_backup.test index 238a8b1985c..ebebb3b2cf9 100644 --- a/mysql-test/suite/mariabackup/rename_during_backup.test +++ b/mysql-test/suite/mariabackup/rename_during_backup.test @@ -90,4 +90,31 @@ SELECT * from t6; DROP TABLE t6; rmdir $targetdir; +--echo # +--echo # MDEV-33011 mariabackup --backup: FATAL ERROR: ... Can't open datafile cool_down/t3 +--echo # +--disable_query_log +call mtr.add_suppression("InnoDB: Cannot rename '.*t1.ibd' to '.*non_existing_db.*' because the target schema directory doesn't exist"); +--enable_query_log + +mkdir $targetdir; + +--echo # Simulate zero initialized page to defer tablespace load after rename log is found +SET @save_dbug = @@SESSION.debug_dbug; +SET DEBUG_DBUG="+d,checkpoint_after_file_create"; +CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB; +INSERT INTO t1 VALUES(1); + +--echo # RENAME that fails after redo log entry is written and flushed +--replace_result "\\" "/" +--error ER_ERROR_ON_RENAME +RENAME TABLE t1 TO non_existing_db.t1; + +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +exec $XTRABACKUP --prepare --target-dir=$targetdir; +--enable_result_log + +DROP TABLE t1; +rmdir $targetdir; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 885b0a700ea..88c1115969a 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1959,14 +1959,14 @@ Allocates and builds a file name from a path, a table or tablespace name and a suffix. The string must be freed by caller with ut_free(). @param[in] path NULL or the directory path or the full path and filename. @param[in] name NULL if path is full, or Table/Tablespace name -@param[in] suffix NULL or the file extention to use. +@param[in] extension NULL or the file extension to use. @param[in] trim_name true if the last name on the path should be trimmed. @return own: file name */ char* -fil_make_filepath( +fil_make_filepath_low( const char* path, const char* name, - ib_extention ext, + ib_extention extension, bool trim_name) { /* The path may contain the basename of the file, if so we do not @@ -1974,10 +1974,6 @@ fil_make_filepath( but there needs to be a name. */ ut_ad(path != NULL || name != NULL); - /* If we are going to strip a name off the path, there better be a - path and a new name to put back on. */ - ut_ad(!trim_name || (path != NULL && name != NULL)); - if (path == NULL) { path = fil_path_to_mysql_datadir; } @@ -1985,7 +1981,7 @@ fil_make_filepath( ulint len = 0; /* current length */ ulint path_len = strlen(path); ulint name_len = (name ? strlen(name) : 0); - const char* suffix = dot_ext[ext]; + const char* suffix = dot_ext[extension]; ulint suffix_len = strlen(suffix); ulint full_len = path_len + 1 + name_len + suffix_len + 1; @@ -2083,6 +2079,21 @@ fil_rename_tablespace_check( } exists = false; + auto schema_path= fil_make_dirpath(new_path, NULL, NO_EXT, true); + if (schema_path == NULL) { + return DB_ERROR; + } + + if (os_file_status(schema_path, &exists, &ftype) && !exists) { + sql_print_error("InnoDB: Cannot rename '%s' to '%s'" + " because the target schema directory doesn't exist.", + old_path, new_path); + ut_free(schema_path); + return DB_ERROR; + } + ut_free(schema_path); + exists = false; + if (os_file_status(new_path, &exists, &ftype) && !exists) { return DB_SUCCESS; } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 10c084bbbf1..1f5589a4a20 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1618,14 +1618,44 @@ Allocates and builds a file name from a path, a table or tablespace name and a suffix. The string must be freed by caller with ut_free(). @param[in] path NULL or the directory path or the full path and filename. @param[in] name NULL if path is full, or Table/Tablespace name -@param[in] suffix NULL or the file extention to use. +@param[in] extension NULL or the file extension to use. +@param[in] trim_name true if the last name on the path should be trimmed. @return own: file name */ char* -fil_make_filepath( +fil_make_filepath_low( const char* path, const char* name, - ib_extention suffix, - bool strip_name); + ib_extention extension, + bool trim_name); + +/** Wrapper function over fil_make_filepath_low to build file name. +@param path NULL or the directory path or the full path and filename. +@param name NULL if path is full, or Table/Tablespace name +@param extension NULL or the file extension to use. +@param trim_name true if the last name on the path should be trimmed. +@return own: file name */ +static inline char* +fil_make_filepath(const char* path, const char* name, ib_extention extension, + bool trim_name) +{ + /* If we are going to strip a name off the path, there better be a + path and a new name to put back on. */ + ut_ad(!trim_name || (path && name)); + return fil_make_filepath_low(path, name, extension, trim_name); +} + +/** Wrapper function over fil_make_filepath_low to build directory name. +@param path NULL or the directory path or the full path and filename. +@param name NULL if path is full, or Table/Tablespace name +@param extension NULL or the file extension to use. +@param trim_name true if the last name on the path should be trimmed. +@return own: directory name */ +static inline char* +fil_make_dirpath(const char* path, const char* name, ib_extention extension, + bool trim_name) +{ + return fil_make_filepath_low(path, name, extension, trim_name); +} /** Create a tablespace file. @param[in] space_id Tablespace ID From 32546877cd75617d33114b85e4a37526ab9ef4bf Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Tue, 12 Dec 2023 05:21:10 +0000 Subject: [PATCH 15/20] MDEV-26923 Check all invalid config options Previously, the behavior was to error out on the first invalid option encountered. With this change, a best effort approach is made so that all invalid options processed will be printed before exiting. There is a caveat. The options are processed many times at varying stages of server startup because the server is not aware of all valid options immediately (e.g. plugins have to be loaded first before the server knows what are the available plugin options). So, there are some options that the server can determine are invalid "early" on, and there are some options that the server cannot determine are invalid until "later" on. For example, the server can determine an option such as `--a` is an ambiguous option very early on but an option such as `--this-does-not-match-any-option` cannot be labelled as invalid until the server is aware of all available options. Thus, it is possible that the server will still fail before printing out all "invalid" options. You can see this by passing `--a --obvious-invalid-option`. Test cases were added to `mysqld_option_err.test` to validate that multiple invalid options will be displayed in the error message. All new code of the whole pull request, including one or several files that are either new files or modified ones, are contributed under the BSD-new license. I am contributing on behalf of my employer Amazon Web Services. --- mysql-test/main/mysqld_option_err.result | 8 ++++ mysql-test/main/mysqld_option_err.test | 12 ++++++ mysys/my_getopt.c | 50 +++++++++++++----------- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/mysql-test/main/mysqld_option_err.result b/mysql-test/main/mysqld_option_err.result index 4afcc5e0cb1..e2c7b0bd213 100644 --- a/mysql-test/main/mysqld_option_err.result +++ b/mysql-test/main/mysqld_option_err.result @@ -3,6 +3,14 @@ Test bad binlog format. Test bad default storage engine. Test non-numeric value passed to number option. Test that bad value for plugin enum option is rejected correctly. +Test to see if multiple unknown options will be displayed in the error output +unknown option '--nonexistentoption' +unknown option '--alsononexistent' +unknown variable 'nonexistentvariable=1' +Test to see if multiple ambiguous options and invalid arguments will be displayed in the error output +Error while setting value 'invalid_value' to 'sql_mode' +ambiguous option '--character' (character-set-client-handshake, character_sets_dir) +option '--bootstrap' cannot take an argument Test that --help --verbose works Test that --not-known-option --help --verbose gives error Done. diff --git a/mysql-test/main/mysqld_option_err.test b/mysql-test/main/mysqld_option_err.test index e9655fd4bfe..ad4df61b0f8 100644 --- a/mysql-test/main/mysqld_option_err.test +++ b/mysql-test/main/mysqld_option_err.test @@ -46,6 +46,18 @@ mkdir $MYSQLTEST_VARDIR/tmp/mysqld_option_err; --error 7 --exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --plugin-dir=$MYSQLTEST_VARDIR/plugins --plugin-load=example=ha_example.so --plugin-example-enum-var=noexist >>$MYSQLTEST_VARDIR/tmp/mysqld_option_err/mysqltest.log 2>&1 +--echo Test to see if multiple unknown options will be displayed in the error output +# Remove the noise to make the test robust +--replace_regex /^((?!nonexistent).)*$// /.*unknown/unknown/ +--error 7 +--exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --nonexistentoption --alsononexistent --nonexistentvariable=1 2>&1 + +--echo Test to see if multiple ambiguous options and invalid arguments will be displayed in the error output +# Remove the noise to make the test robust +--replace_regex /^((?!('sql_mode'|'--character'|'--bootstrap')).)*$// /.*Error while setting value/Error while setting value/ /.*ambiguous option/ambiguous option/ /.*option '--bootstrap'/option '--bootstrap'/ +--error 1 +--exec $MYSQLD_BOOTSTRAP_CMD --skip-networking --datadir=$MYSQLTEST_VARDIR/tmp/mysqld_option_err --skip-grant-tables --getopt-prefix-matching --sql-mode=invalid_value --character --bootstrap=partstoob 2>&1 + # # Test that an wrong option with --help --verbose gives an error # diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index cb0e0e61240..be8a89d2b08 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -133,6 +133,8 @@ double getopt_ulonglong2double(ulonglong v) return u.dbl; } +#define SET_HO_ERROR_AND_CONTINUE(e) { ho_error= (e); continue; } + /** Handle command line options. Sort options. @@ -202,7 +204,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, const char *UNINIT_VAR(prev_found); const struct my_option *optp; void *value; - int error, i; + int ho_error= 0, error, i; my_bool is_cmdline_arg= 1; DBUG_ENTER("handle_options"); @@ -216,7 +218,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, is_cmdline_arg= !is_file_marker(**argv); - for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) + for (pos= *argv, pos_end=pos+ *argc; pos < pos_end ; pos++) { char **first= pos; char *cur_arg= *pos; @@ -305,7 +307,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_progname, special_opt_prefix[i], opt_str, special_opt_prefix[i], prev_found); - DBUG_RETURN(EXIT_AMBIGUOUS_OPTION); + SET_HO_ERROR_AND_CONTINUE(EXIT_AMBIGUOUS_OPTION) } switch (i) { case OPT_SKIP: @@ -350,7 +352,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, "%s: unknown variable '%s'", my_progname, cur_arg); if (!option_is_loose) - DBUG_RETURN(EXIT_UNKNOWN_VARIABLE); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNKNOWN_VARIABLE) } else { @@ -360,7 +362,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, "%s: unknown option '--%s'", my_progname, cur_arg); if (!option_is_loose) - DBUG_RETURN(EXIT_UNKNOWN_OPTION); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNKNOWN_OPTION) } if (option_is_loose) { @@ -377,7 +379,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_getopt_error_reporter(ERROR_LEVEL, "%s: variable prefix '%s' is not unique", my_progname, opt_str); - DBUG_RETURN(EXIT_VAR_PREFIX_NOT_UNIQUE); + SET_HO_ERROR_AND_CONTINUE(EXIT_VAR_PREFIX_NOT_UNIQUE) } else { @@ -386,7 +388,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, "%s: ambiguous option '--%s' (%s, %s)", my_progname, opt_str, prev_found, optp->name); - DBUG_RETURN(EXIT_AMBIGUOUS_OPTION); + SET_HO_ERROR_AND_CONTINUE(EXIT_AMBIGUOUS_OPTION) } } if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED) @@ -400,14 +402,14 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, (*argc)--; continue; } - DBUG_RETURN(EXIT_OPTION_DISABLED); + SET_HO_ERROR_AND_CONTINUE(EXIT_OPTION_DISABLED) } error= 0; value= optp->var_type & GET_ASK_ADDR ? (*my_getopt_get_addr)(key_name, (uint)strlen(key_name), optp, &error) : optp->value; if (error) - DBUG_RETURN(error); + SET_HO_ERROR_AND_CONTINUE(error) if (optp->arg_type == NO_ARG) { @@ -422,7 +424,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_getopt_error_reporter(ERROR_LEVEL, "%s: option '--%s' cannot take an argument", my_progname, optp->name); - DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED); + SET_HO_ERROR_AND_CONTINUE(EXIT_NO_ARGUMENT_ALLOWED) } if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL) { @@ -451,7 +453,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, if (get_one_option(optp, *((my_bool*) value) ? enabled_my_option : disabled_my_option, filename)) - DBUG_RETURN(EXIT_ARGUMENT_INVALID); + SET_HO_ERROR_AND_CONTINUE(EXIT_ARGUMENT_INVALID) continue; } argument= optend; @@ -465,7 +467,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, "option '--%s' cannot take an argument", my_progname, optp->name); - DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED); + SET_HO_ERROR_AND_CONTINUE(EXIT_NO_ARGUMENT_ALLOWED) } if (!(optp->var_type & GET_AUTO)) { @@ -475,7 +477,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, "unsupported by option '--%s'", my_progname, optp->name); if (!option_is_loose) - DBUG_RETURN(EXIT_ARGUMENT_INVALID); + SET_HO_ERROR_AND_CONTINUE(EXIT_ARGUMENT_INVALID) continue; } else @@ -494,7 +496,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_getopt_error_reporter(ERROR_LEVEL, "%s: option '--%s' requires an argument", my_progname, optp->name); - DBUG_RETURN(EXIT_ARGUMENT_REQUIRED); + SET_HO_ERROR_AND_CONTINUE(EXIT_ARGUMENT_REQUIRED) } argument= *pos; (*argc)--; @@ -519,14 +521,14 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, fprintf(stderr, "%s: ERROR: Option '-%c' used, but is disabled\n", my_progname, optp->id); - DBUG_RETURN(EXIT_OPTION_DISABLED); + SET_HO_ERROR_AND_CONTINUE(EXIT_OPTION_DISABLED) } if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL && optp->arg_type == NO_ARG) { *((my_bool*) optp->value)= (my_bool) 1; if (get_one_option(optp, argument, filename)) - DBUG_RETURN(EXIT_UNSPECIFIED_ERROR); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNSPECIFIED_ERROR) continue; } else if (optp->arg_type == REQUIRED_ARG || @@ -546,7 +548,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, if (optp->var_type == GET_BOOL) *((my_bool*) optp->value)= (my_bool) 1; if (get_one_option(optp, argument, filename)) - DBUG_RETURN(EXIT_UNSPECIFIED_ERROR); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNSPECIFIED_ERROR) continue; } /* Check if there are more arguments after this one */ @@ -556,7 +558,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_getopt_error_reporter(ERROR_LEVEL, "%s: option '-%c' requires an argument", my_progname, optp->id); - DBUG_RETURN(EXIT_ARGUMENT_REQUIRED); + SET_HO_ERROR_AND_CONTINUE(EXIT_ARGUMENT_REQUIRED) } argument= *++pos; (*argc)--; @@ -565,9 +567,9 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, } if ((error= setval(optp, optp->value, argument, set_maximum_value))) - DBUG_RETURN(error); + SET_HO_ERROR_AND_CONTINUE(error) if (get_one_option(optp, argument, filename)) - DBUG_RETURN(EXIT_UNSPECIFIED_ERROR); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNSPECIFIED_ERROR) break; } } @@ -601,7 +603,7 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, my_getopt_error_reporter(ERROR_LEVEL, "%s: unknown option '-%c'", my_progname, *optend); - DBUG_RETURN(EXIT_UNKNOWN_OPTION); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNKNOWN_OPTION) } } } @@ -612,15 +614,17 @@ int handle_options(int *argc, char ***argv, const struct my_option *longopts, if ((!option_is_autoset) && ((error= setval(optp, value, argument, set_maximum_value))) && !option_is_loose) - DBUG_RETURN(error); + SET_HO_ERROR_AND_CONTINUE(error) if (get_one_option(optp, argument, filename)) - DBUG_RETURN(EXIT_UNSPECIFIED_ERROR); + SET_HO_ERROR_AND_CONTINUE(EXIT_UNSPECIFIED_ERROR) (*argc)--; /* option handled (long), decrease argument count */ } else /* non-option found */ (*argv)[argvpos++]= cur_arg; } + if (ho_error) + DBUG_RETURN(ho_error); /* Destroy the first, already handled option, so that programs that look for arguments in 'argv', without checking 'argc', know when to stop. From 8b3f470c0bdf183b26cb2b06a9ae416aa7f16b04 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 1 Mar 2024 11:21:50 +0200 Subject: [PATCH 16/20] Fixed random failure in main.kill_processlist-6619 The problem was that SHOW PROCESSLIST was done before the command of the default connection was cleared. Reviewer: Sergei Golubchik --- mysql-test/main/kill_processlist-6619.result | 6 ++++++ mysql-test/main/kill_processlist-6619.test | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/mysql-test/main/kill_processlist-6619.result b/mysql-test/main/kill_processlist-6619.result index 7dd42790cc7..25831a1f63b 100644 --- a/mysql-test/main/kill_processlist-6619.result +++ b/mysql-test/main/kill_processlist-6619.result @@ -1,4 +1,8 @@ +SET DEBUG_SYNC='dispatch_command_end SIGNAL ready WAIT_FOR go'; +select 1; connect con1,localhost,root,,; +SET DEBUG_SYNC='now wait_for ready'; +SET DEBUG_SYNC='now signal go'; SHOW PROCESSLIST; Id User Host db Command Time State Info Progress # root # test Sleep # # NULL 0.000 @@ -6,6 +10,8 @@ Id User Host db Command Time State Info Progress SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go'; SHOW PROCESSLIST; connection default; +1 +1 SET DEBUG_SYNC='now WAIT_FOR ready'; KILL QUERY con_id; SET DEBUG_SYNC='now SIGNAL go'; diff --git a/mysql-test/main/kill_processlist-6619.test b/mysql-test/main/kill_processlist-6619.test index c272e68a877..7330c79acd8 100644 --- a/mysql-test/main/kill_processlist-6619.test +++ b/mysql-test/main/kill_processlist-6619.test @@ -4,7 +4,14 @@ --source include/not_embedded.inc --source include/have_debug_sync.inc +# This is to ensure that the following SHOW PROCESSLIST does not show the query +SET DEBUG_SYNC='dispatch_command_end SIGNAL ready WAIT_FOR go'; +--send select 1 + --connect (con1,localhost,root,,) +SET DEBUG_SYNC='now wait_for ready'; +SET DEBUG_SYNC='now signal go'; + --let $con_id = `SELECT CONNECTION_ID()` --replace_result Execute Query --replace_column 1 # 3 # 6 # 7 # @@ -12,6 +19,8 @@ SHOW PROCESSLIST; SET DEBUG_SYNC='before_execute_sql_command SIGNAL ready WAIT_FOR go'; send SHOW PROCESSLIST; --connection default +--reap + # We must wait for the SHOW PROCESSLIST query to have started before sending # the kill. Otherwise, the KILL may be lost since it is reset at the start of # query execution. From d37c51b8053344b52fd9c539c3964070a9c0b307 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Tue, 20 Feb 2024 11:20:21 +1100 Subject: [PATCH 17/20] MDEV-33494 fix spider init with no_zero_date global sql mode Like the fix for MDEV-32753 and MDEV-33242, spider init queries creates new connections that use the global sql_mode of the existing connection. --- .../mysql-test/spider/bugfix/r/mdev_33494.result | 4 ++++ .../spider/mysql-test/spider/bugfix/t/mdev_33494.test | 11 +++++++++++ storage/spider/spd_init_query.h | 2 +- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_33494.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_33494.test diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_33494.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_33494.result new file mode 100644 index 00000000000..3db28c0f08e --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_33494.result @@ -0,0 +1,4 @@ +set @old_sql_mode=@@global.sql_mode; +set global sql_mode=(SELECT CONCAT (@@sql_mode,',no_zero_date')); +install soname 'ha_spider'; +set global sql_mode=@old_sql_mode; diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_33494.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_33494.test new file mode 100644 index 00000000000..30beca77f35 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_33494.test @@ -0,0 +1,11 @@ +# This test tests spider init with global no_zero_date sql mode +set @old_sql_mode=@@global.sql_mode; +set global sql_mode=(SELECT CONCAT (@@sql_mode,',no_zero_date')); +install soname 'ha_spider'; +set global sql_mode=@old_sql_mode; + +--disable_query_log +--disable_result_log +--source ../../include/clean_up_spider.inc +--enable_result_log +--enable_query_log diff --git a/storage/spider/spd_init_query.h b/storage/spider/spd_init_query.h index cf41e47f890..83f1968f8b2 100644 --- a/storage/spider/spd_init_query.h +++ b/storage/spider/spd_init_query.h @@ -21,7 +21,7 @@ static LEX_STRING spider_init_queries[] = { {C_STRING_WITH_LEN( - "SET @@SQL_MODE = REPLACE(@@SQL_MODE, 'ORACLE', '');" + "SET @@SQL_MODE = REGEXP_REPLACE(@@SQL_MODE, '(ORACLE|NO_ZERO_DATE)', '');" )}, {C_STRING_WITH_LEN( "create table if not exists mysql.spider_xa(" From 1b568fb917e98e5bb2e1387fcfb63de2d10c652b Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 26 Feb 2024 15:00:54 +1100 Subject: [PATCH 18/20] MDEV-33539 spider: remove some unused code in self reference checks --- storage/spider/spd_db_conn.cc | 8 --- storage/spider/spd_db_include.cc | 16 ----- storage/spider/spd_db_include.h | 4 -- storage/spider/spd_db_mysql.cc | 109 ------------------------------- storage/spider/spd_db_mysql.h | 5 -- storage/spider/spd_include.h | 1 - 6 files changed, 143 deletions(-) diff --git a/storage/spider/spd_db_conn.cc b/storage/spider/spd_db_conn.cc index 6bfc63a3813..37dbfb75aaa 100644 --- a/storage/spider/spd_db_conn.cc +++ b/storage/spider/spd_db_conn.cc @@ -378,7 +378,6 @@ int spider_db_conn_queue_action( ) || ( conn->loop_check_queue.records && - conn->db_conn->set_loop_check_in_bulk_sql() && (error_num = spider_dbton[conn->dbton_id].db_util-> append_loop_check(&sql_str, conn)) ) || @@ -477,13 +476,6 @@ int spider_db_conn_queue_action( ) { DBUG_RETURN(error_num); } - if ( - conn->loop_check_queue.records && - !conn->db_conn->set_loop_check_in_bulk_sql() && - (error_num = conn->db_conn->set_loop_check((int *) conn->need_mon)) - ) { - DBUG_RETURN(error_num); - } if ( conn->queued_trx_isolation && !conn->queued_semi_trx_isolation && diff --git a/storage/spider/spd_db_include.cc b/storage/spider/spd_db_include.cc index b9a0532d1b9..d74ad444179 100644 --- a/storage/spider/spd_db_include.cc +++ b/storage/spider/spd_db_include.cc @@ -71,22 +71,6 @@ spider_db_conn::spider_db_conn( DBUG_VOID_RETURN; } -bool spider_db_conn::set_loop_check_in_bulk_sql() -{ - DBUG_ENTER("spider_db_conn::set_loop_check_in_bulk_sql"); - DBUG_PRINT("info",("spider this=%p", this)); - DBUG_RETURN(FALSE); -} - -int spider_db_conn::set_loop_check( - int *need_mon -) { - DBUG_ENTER("spider_db_conn::set_loop_check"); - DBUG_PRINT("info",("spider this=%p", this)); - /* nothing to do */ - DBUG_RETURN(0); -} - int spider_db_conn::fin_loop_check() { st_spider_conn_loop_check *lcptr; diff --git a/storage/spider/spd_db_include.h b/storage/spider/spd_db_include.h index 4fecad86063..8ecdb4ff425 100644 --- a/storage/spider/spd_db_include.h +++ b/storage/spider/spd_db_include.h @@ -1170,10 +1170,6 @@ public: Time_zone *time_zone, int *need_mon ) = 0; - virtual bool set_loop_check_in_bulk_sql(); - virtual int set_loop_check( - int *need_mon - ); virtual int fin_loop_check(); virtual int show_master_status( SPIDER_TRX *trx, diff --git a/storage/spider/spd_db_mysql.cc b/storage/spider/spd_db_mysql.cc index e184040c69f..cd88e187dfd 100644 --- a/storage/spider/spd_db_mysql.cc +++ b/storage/spider/spd_db_mysql.cc @@ -3352,115 +3352,6 @@ int spider_db_mbase::set_time_zone( DBUG_RETURN(0); } -bool spider_db_mbase::set_loop_check_in_bulk_sql() -{ - DBUG_ENTER("spider_db_mbase::set_loop_check_in_bulk_sql"); - DBUG_PRINT("info",("spider this=%p", this)); - DBUG_RETURN(TRUE); -} - -int spider_db_mbase::set_loop_check( - int *need_mon -) { - SPIDER_CONN_LOOP_CHECK *lcptr; - char sql_buf[MAX_FIELD_WIDTH]; - spider_string sql_str(sql_buf, sizeof(sql_buf), &my_charset_bin); - DBUG_ENTER("spider_db_mbase::set_loop_check"); - DBUG_PRINT("info",("spider this=%p", this)); - sql_str.init_calc_mem(SPD_MID_DB_MBASE_SET_LOOP_CHECK_1); - while ((lcptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_element( - &conn->loop_check_queue, 0))) - { - sql_str.length(0); - if (sql_str.reserve(SPIDER_SQL_SET_USER_VAL_LEN + - SPIDER_SQL_LOP_CHK_PRM_PRF_LEN + lcptr->to_name.length + - SPIDER_SQL_NAME_QUOTE_LEN + SPIDER_SQL_EQUAL_LEN + - SPIDER_SQL_VALUE_QUOTE_LEN + - lcptr->merged_value.length + SPIDER_SQL_VALUE_QUOTE_LEN)) - { - DBUG_RETURN(HA_ERR_OUT_OF_MEM); - } - sql_str.q_append(SPIDER_SQL_SET_USER_VAL_STR, SPIDER_SQL_SET_USER_VAL_LEN); - sql_str.q_append(SPIDER_SQL_LOP_CHK_PRM_PRF_STR, - SPIDER_SQL_LOP_CHK_PRM_PRF_LEN); - sql_str.q_append(lcptr->to_name.str, lcptr->to_name.length); - sql_str.q_append(SPIDER_SQL_NAME_QUOTE_STR, SPIDER_SQL_NAME_QUOTE_LEN); - sql_str.q_append(SPIDER_SQL_EQUAL_STR, SPIDER_SQL_EQUAL_LEN); - sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN); - sql_str.q_append(lcptr->merged_value.str, lcptr->merged_value.length); - sql_str.q_append(SPIDER_SQL_VALUE_QUOTE_STR, SPIDER_SQL_VALUE_QUOTE_LEN); - - pthread_mutex_assert_not_owner(&conn->mta_conn_mutex); - pthread_mutex_lock(&conn->mta_conn_mutex); - SPIDER_SET_FILE_POS(&conn->mta_conn_mutex_file_pos); - conn->need_mon = need_mon; - DBUG_ASSERT(!conn->mta_conn_mutex_lock_already); - DBUG_ASSERT(!conn->mta_conn_mutex_unlock_later); - conn->mta_conn_mutex_lock_already = TRUE; - conn->mta_conn_mutex_unlock_later = TRUE; - if (spider_db_query( - conn, - sql_str.ptr(), - sql_str.length(), - -1, - need_mon) - ) { - DBUG_ASSERT(conn->mta_conn_mutex_lock_already); - DBUG_ASSERT(conn->mta_conn_mutex_unlock_later); - conn->mta_conn_mutex_lock_already = FALSE; - conn->mta_conn_mutex_unlock_later = FALSE; - DBUG_RETURN(spider_db_errorno(conn)); - } - DBUG_ASSERT(conn->mta_conn_mutex_lock_already); - DBUG_ASSERT(conn->mta_conn_mutex_unlock_later); - conn->mta_conn_mutex_lock_already = FALSE; - conn->mta_conn_mutex_unlock_later = FALSE; - SPIDER_CLEAR_FILE_POS(&conn->mta_conn_mutex_file_pos); - pthread_mutex_unlock(&conn->mta_conn_mutex); - -#ifdef HASH_UPDATE_WITH_HASH_VALUE - my_hash_delete_with_hash_value(&conn->loop_check_queue, - lcptr->hash_value, (uchar *) lcptr); -#else - my_hash_delete(&conn->loop_check_queue, (uchar*) lcptr); -#endif - } - DBUG_RETURN(0); -} - -int spider_db_mbase::fin_loop_check() -{ - st_spider_conn_loop_check *lcptr; - DBUG_ENTER("spider_db_mbase::fin_loop_check"); - DBUG_PRINT("info",("spider this=%p", this)); - if (conn->loop_check_queue.records) - { - uint l = 0; - while ((lcptr = (SPIDER_CONN_LOOP_CHECK *) my_hash_element( - &conn->loop_check_queue, l))) - { - lcptr->flag = 0; - ++l; - } - my_hash_reset(&conn->loop_check_queue); - } - lcptr = conn->loop_check_ignored_first; - while (lcptr) - { - lcptr->flag = 0; - lcptr = lcptr->next; - } - conn->loop_check_ignored_first = NULL; - lcptr = conn->loop_check_meraged_first; - while (lcptr) - { - lcptr->flag = 0; - lcptr = lcptr->next; - } - conn->loop_check_meraged_first = NULL; - DBUG_RETURN(0); -} - int spider_db_mbase::exec_simple_sql_with_result( SPIDER_TRX *trx, SPIDER_SHARE *share, diff --git a/storage/spider/spd_db_mysql.h b/storage/spider/spd_db_mysql.h index 67d6fabcc2f..9e4d0e8f261 100644 --- a/storage/spider/spd_db_mysql.h +++ b/storage/spider/spd_db_mysql.h @@ -527,11 +527,6 @@ public: Time_zone *time_zone, int *need_mon ); - bool set_loop_check_in_bulk_sql(); - int set_loop_check( - int *need_mon - ); - int fin_loop_check(); int exec_simple_sql_with_result( SPIDER_TRX *trx, SPIDER_SHARE *share, diff --git a/storage/spider/spd_include.h b/storage/spider/spd_include.h index e2ee47884e3..519ae03a5b6 100644 --- a/storage/spider/spd_include.h +++ b/storage/spider/spd_include.h @@ -377,7 +377,6 @@ enum spider_malloc_id { SPD_MID_DB_MBASE_RESULT_FETCH_ROW_FROM_TMP_TABLE_3, SPD_MID_DB_MBASE_ROW_APPEND_ESCAPED_TO_STR_1, SPD_MID_DB_MBASE_ROW_CLONE_1, - SPD_MID_DB_MBASE_SET_LOOP_CHECK_1, SPD_MID_DB_MBASE_SET_SQL_MODE_1, SPD_MID_DB_MBASE_SET_TIME_ZONE_1, SPD_MID_DB_MBASE_SET_WAIT_TIMEOUT_1, From 6e5333fc8cf9efaee2abc7e34982a862c2268284 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 4 Mar 2024 18:50:12 +0530 Subject: [PATCH 19/20] MDEV-32445 InnoDB may corrupt its log before upgrading it on startup Problem: ======== During upgrade, InnoDB does write the redo log for adjusting the tablespace size or tablespace flags even before the log has upgraded to configured format. This could lead to data inconsistent if any crash happened during upgrade process. Fix: === srv_start(): Write the tablespace flags adjustment, increased tablespace size redo log only after redo log upgradation. log_write_low(), log_reserve_and_write_fast(): Check whether the redo log is in physical format. --- .../innodb/r/log_upgrade_101_flags.result | 12 ++ .../suite/innodb/t/log_upgrade_101_flags.test | 91 ++++++++ storage/innobase/include/log0log.inl | 1 + storage/innobase/mtr/mtr0mtr.cc | 2 + storage/innobase/srv/srv0start.cc | 194 +++++++++--------- 5 files changed, 202 insertions(+), 98 deletions(-) create mode 100644 mysql-test/suite/innodb/r/log_upgrade_101_flags.result create mode 100644 mysql-test/suite/innodb/t/log_upgrade_101_flags.test diff --git a/mysql-test/suite/innodb/r/log_upgrade_101_flags.result b/mysql-test/suite/innodb/r/log_upgrade_101_flags.result new file mode 100644 index 00000000000..6ae7c84807f --- /dev/null +++ b/mysql-test/suite/innodb/r/log_upgrade_101_flags.result @@ -0,0 +1,12 @@ +call mtr.add_suppression("InnoDB: The change buffer is corrupted"); +call mtr.add_suppression("InnoDB: Tablespace size stored in header is 768 pages, but the sum of data file sizes is 384 pages"); +call mtr.add_suppression("InnoDB: adjusting FSP_SPACE_FLAGS of file"); +# restart: --innodb-data-home-dir=MYSQLTEST_VARDIR/tmp/log_upgrade --innodb-log-group-home-dir=MYSQLTEST_VARDIR/tmp/log_upgrade --innodb-force-recovery=5 --innodb-log-file-size=4m --innodb_page_size=32k --innodb_buffer_pool_size=10M +SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +COUNT(*) +1 +FOUND 1 /InnoDB: Upgrading redo log:/ in mysqld.1.err +# restart +# End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/log_upgrade_101_flags.test b/mysql-test/suite/innodb/t/log_upgrade_101_flags.test new file mode 100644 index 00000000000..4358ccfa1ca --- /dev/null +++ b/mysql-test/suite/innodb/t/log_upgrade_101_flags.test @@ -0,0 +1,91 @@ +--source include/have_innodb.inc +--source include/big_test.inc +--source include/not_embedded.inc +call mtr.add_suppression("InnoDB: The change buffer is corrupted"); +call mtr.add_suppression("InnoDB: Tablespace size stored in header is 768 pages, but the sum of data file sizes is 384 pages"); +call mtr.add_suppression("InnoDB: adjusting FSP_SPACE_FLAGS of file"); +--source include/shutdown_mysqld.inc +let bugdir= $MYSQLTEST_VARDIR/tmp/log_upgrade; +--mkdir $bugdir +--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err +--let $dirs= --innodb-data-home-dir=$bugdir --innodb-log-group-home-dir=$bugdir + +# Test case similar to log_upgrade.test +perl; +do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl"; +my $polynomial = 0x82f63b78; # CRC-32C + +die unless open OUT, ">", "$ENV{bugdir}/ibdata1"; +binmode OUT; + +my $head = pack("Nx[18]", 0); +# Add FSP_SPACE_FLAGS as 49152 (10.1.0...10.1.20), page_size = 32k +my $body = pack("x[8]Nx[4]Nx[2]Nx[32696]", 768, 49152, 97937874); +my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); +# Dummy pages 1..6. +print OUT chr(0) x (6 * 32768); +# Dictionary header page (page 7). +$head = pack("Nx[18]", 7); +$body = pack("x[32]Nx[8]Nx[32674]", 8, 9); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +# Empty SYS_TABLES page (page 8). +$head = pack("NNNx[8]n", 8, ~0, ~0, 17855); +$body = pack("nnx[31]Cx[20]", 2, 124, 1); +$body .= pack("nxnn", 0x801, 3, 116) . "infimum"; +$body .= pack("xnxnxx", 0x901, 0x803) . "supremum"; +$body .= pack("x[32632]nn", 116, 101); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +# Empty SYS_INDEXES page (page 9). +$head = pack("NNNx[8]n", 9, ~0, ~0, 17855); +$body = pack("nnx[31]Cx[20]", 2, 124, 3); +$body .= pack("nxnn", 0x801, 3, 116) . "infimum"; +$body .= pack("xnxnxx", 0x901, 0x803) . "supremum"; +$body .= pack("x[32632]nn", 116, 101); +$ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial); +print OUT pack("N",$ck).$head.pack("x[12]").$body.pack("Nx[4]",$ck); + +die unless seek(OUT, 768 * 16384 - 1, 0); +print OUT chr(0); +close OUT or die; + +die unless open OUT, ">", "$ENV{bugdir}/ib_logfile0"; +binmode OUT; +$_= pack("Nx[5]nx[5]", 1, 0x1286) . "BogoDB 4.3.2.1" . chr(0) x 478; +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +# checkpoint page 1 and all-zero checkpoint 2 +$_= pack("x[13]nCNNx[484]", 0x1286, 12, 2, 0x80c); +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +die unless seek(OUT, 0x1FFFFFFFF, 0); +print OUT chr(0); +close OUT or die; +die unless open OUT, ">", "$ENV{bugdir}/ib_logfile1"; +binmode OUT; +die unless seek(OUT, 0x800, 0); # the first 2048 bytes are unused! +$_= pack("Nnnx[500]", 0x80000944, 12, 12); +print OUT $_, pack("N", mycrc32($_, 0, $polynomial)); +die unless seek(OUT, 0x1FFFFFFFF, 0); +print OUT chr(0); +close OUT or die; +EOF + +--let $restart_parameters= $dirs --innodb-force-recovery=5 --innodb-log-file-size=4m --innodb_page_size=32k --innodb_buffer_pool_size=10M +--source include/start_mysqld.inc +SELECT COUNT(*) FROM INFORMATION_SCHEMA.ENGINES +WHERE engine = 'innodb' +AND support IN ('YES', 'DEFAULT', 'ENABLED'); +--source include/shutdown_mysqld.inc +--let SEARCH_PATTERN= InnoDB: Upgrading redo log: +--source include/search_pattern_in_file.inc +--let $restart_parameters= $dirs + +--remove_files_wildcard $bugdir +--rmdir $bugdir +--let $restart_parameters= +--source include/start_mysqld.inc + +--echo # End of 10.5 tests diff --git a/storage/innobase/include/log0log.inl b/storage/innobase/include/log0log.inl index 0ff8c2523d7..8dd6f6ad573 100644 --- a/storage/innobase/include/log0log.inl +++ b/storage/innobase/include/log0log.inl @@ -270,6 +270,7 @@ log_reserve_and_write_fast( } lsn_t lsn = log_sys.get_lsn(); + ut_ad(log_sys.is_physical()); *start_lsn = lsn; memcpy(log_sys.buf + log_sys.buf_free, str, len); diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index dd9036f9e08..bf4b2b6b07c 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -850,6 +850,8 @@ static void log_write_low(const void *str, size_t size) len= trailer_offset - log_sys.buf_free % OS_FILE_LOG_BLOCK_SIZE; } + ut_ad(log_sys.is_physical()); + memcpy(log_sys.buf + log_sys.buf_free, str, len); size-= len; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 4382a318367..cd16b3265f6 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1555,6 +1555,102 @@ dberr_t srv_start(bool create_new_db) fil_system.space_id_reuse_warned = false; + if (srv_operation == SRV_OPERATION_RESTORE + || srv_operation == SRV_OPERATION_RESTORE_EXPORT) { + buf_flush_sync(); + recv_sys.debug_free(); + /* After applying the redo log from + SRV_OPERATION_BACKUP, flush the changes + to the data files and truncate or delete the log. + Unless --export is specified, no further change to + InnoDB files is needed. */ + ut_ad(srv_force_recovery <= SRV_FORCE_IGNORE_CORRUPT); + ut_ad(recv_no_log_write); + err = fil_write_flushed_lsn(log_sys.get_lsn()); + DBUG_ASSERT(!buf_pool.any_io_pending()); + log_sys.log.close_file(); + if (err == DB_SUCCESS) { + bool trunc = srv_operation + == SRV_OPERATION_RESTORE; + if (!trunc) { + delete_log_file("0"); + } else { + auto logfile0 = get_log_file_path(); + /* Truncate the first log file. */ + fclose(fopen(logfile0.c_str(), "w")); + } + } + return(err); + } + /* Upgrade or resize or rebuild the redo logs before + generating any dirty pages, so that the old redo log + file will not be written to. */ + + if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) { + /* Completely ignore the redo log. */ + } else if (srv_read_only_mode) { + /* Leave the redo log alone. */ + } else if (srv_log_file_size_requested == srv_log_file_size + && srv_log_file_found + && log_sys.log.format + == (srv_encrypt_log + ? log_t::FORMAT_ENC_10_5 + : log_t::FORMAT_10_5) + && log_sys.log.subformat == 2) { + /* No need to add or remove encryption, + upgrade, downgrade, or resize. */ + } else { + /* Prepare to delete the old redo log file */ + flushed_lsn = srv_prepare_to_delete_redo_log_file( + srv_log_file_found); + + DBUG_EXECUTE_IF("innodb_log_abort_1", + return(srv_init_abort(DB_ERROR));); + /* 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); + DBUG_ASSERT(!buf_pool.any_io_pending()); + + DBUG_EXECUTE_IF("innodb_log_abort_3", + return(srv_init_abort(DB_ERROR));); + DBUG_PRINT("ib_log", ("After innodb_log_abort_3")); + + /* Stamp the LSN to the data files. */ + err = fil_write_flushed_lsn(flushed_lsn); + + DBUG_EXECUTE_IF("innodb_log_abort_4", err = DB_ERROR;); + DBUG_PRINT("ib_log", ("After innodb_log_abort_4")); + + if (err != DB_SUCCESS) { + return(srv_init_abort(err)); + } + + /* Close the redo log file, so that we can replace it */ + log_sys.log.close_file(); + + DBUG_EXECUTE_IF("innodb_log_abort_5", + return(srv_init_abort(DB_ERROR));); + DBUG_PRINT("ib_log", ("After innodb_log_abort_5")); + + ib::info() + << "Starting to delete and rewrite log file."; + + srv_log_file_size = srv_log_file_size_requested; + + err = create_log_file(false, flushed_lsn, logfile0); + + if (err == DB_SUCCESS) { + err = create_log_file_rename(flushed_lsn, + logfile0); + } + + if (err != DB_SUCCESS) { + return(srv_init_abort(err)); + } + } + recv_sys.debug_free(); + if (!srv_read_only_mode) { const ulint flags = FSP_FLAGS_PAGE_SSIZE(); for (ulint id = 0; id <= srv_undo_tablespaces; id++) { @@ -1639,104 +1735,6 @@ dberr_t srv_start(bool create_new_db) return(srv_init_abort(DB_ERROR)); } } - - if (srv_operation == SRV_OPERATION_RESTORE - || srv_operation == SRV_OPERATION_RESTORE_EXPORT) { - buf_flush_sync(); - recv_sys.debug_free(); - /* After applying the redo log from - SRV_OPERATION_BACKUP, flush the changes - to the data files and truncate or delete the log. - Unless --export is specified, no further change to - InnoDB files is needed. */ - ut_ad(srv_force_recovery <= SRV_FORCE_IGNORE_CORRUPT); - ut_ad(recv_no_log_write); - err = fil_write_flushed_lsn(log_sys.get_lsn()); - DBUG_ASSERT(!buf_pool.any_io_pending()); - log_sys.log.close_file(); - if (err == DB_SUCCESS) { - bool trunc = srv_operation - == SRV_OPERATION_RESTORE; - if (!trunc) { - delete_log_file("0"); - } else { - auto logfile0 = get_log_file_path(); - /* Truncate the first log file. */ - fclose(fopen(logfile0.c_str(), "w")); - } - } - return(err); - } - - /* Upgrade or resize or rebuild the redo logs before - generating any dirty pages, so that the old redo log - file will not be written to. */ - - if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) { - /* Completely ignore the redo log. */ - } else if (srv_read_only_mode) { - /* Leave the redo log alone. */ - } else if (srv_log_file_size_requested == srv_log_file_size - && srv_log_file_found - && log_sys.log.format - == (srv_encrypt_log - ? log_t::FORMAT_ENC_10_5 - : log_t::FORMAT_10_5) - && log_sys.log.subformat == 2) { - /* No need to add or remove encryption, - upgrade, downgrade, or resize. */ - } else { - /* Prepare to delete the old redo log file */ - flushed_lsn = srv_prepare_to_delete_redo_log_file( - srv_log_file_found); - - DBUG_EXECUTE_IF("innodb_log_abort_1", - return(srv_init_abort(DB_ERROR));); - /* 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); - DBUG_ASSERT(!buf_pool.any_io_pending()); - - DBUG_EXECUTE_IF("innodb_log_abort_3", - return(srv_init_abort(DB_ERROR));); - DBUG_PRINT("ib_log", ("After innodb_log_abort_3")); - - /* Stamp the LSN to the data files. */ - err = fil_write_flushed_lsn(flushed_lsn); - - DBUG_EXECUTE_IF("innodb_log_abort_4", err = DB_ERROR;); - DBUG_PRINT("ib_log", ("After innodb_log_abort_4")); - - if (err != DB_SUCCESS) { - return(srv_init_abort(err)); - } - - /* Close the redo log file, so that we can replace it */ - log_sys.log.close_file(); - - DBUG_EXECUTE_IF("innodb_log_abort_5", - return(srv_init_abort(DB_ERROR));); - DBUG_PRINT("ib_log", ("After innodb_log_abort_5")); - - ib::info() - << "Starting to delete and rewrite log file."; - - srv_log_file_size = srv_log_file_size_requested; - - err = create_log_file(false, flushed_lsn, logfile0); - - if (err == DB_SUCCESS) { - err = create_log_file_rename(flushed_lsn, - logfile0); - } - - if (err != DB_SUCCESS) { - return(srv_init_abort(err)); - } - } - - recv_sys.debug_free(); } ut_ad(err == DB_SUCCESS); From afe9632913d5ed4c8d2aa81308f449e31766abaa Mon Sep 17 00:00:00 2001 From: mariadb-DebarunBanerjee Date: Tue, 5 Mar 2024 12:07:48 +0530 Subject: [PATCH 20/20] MDEV-33593 Auto increment deadlock error causes ASSERT in subsequent save point The issue here is ha_innobase::get_auto_increment() could cause a deadlock involving auto-increment lock and rollback the transaction implicitly. For such cases, storage engines usually call thd_mark_transaction_to_rollback() to inform SQL engine about it which in turn takes appropriate actions and close the transaction. In innodb, we call it while converting Innodb error code to MySQL. However, since ::innobase_get_autoinc() returns void, we skip the call for error code conversion and also miss marking the transaction for rollback for deadlock error. We assert eventually while releasing a savepoint as the transaction state is not active. Since convert_error_code_to_mysql() is handling some generic error handling part, like invoking the callback when needed, we should call that function in ha_innobase::get_auto_increment() even if we don't return the resulting mysql error code back. --- .../suite/innodb/r/autoinc_debug.result | 55 ++++++++++++++++ mysql-test/suite/innodb/t/autoinc_debug.test | 64 +++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 7 ++ storage/innobase/lock/lock0lock.cc | 2 + 4 files changed, 128 insertions(+) diff --git a/mysql-test/suite/innodb/r/autoinc_debug.result b/mysql-test/suite/innodb/r/autoinc_debug.result index b3b7a469ada..94406a80ab5 100644 --- a/mysql-test/suite/innodb/r/autoinc_debug.result +++ b/mysql-test/suite/innodb/r/autoinc_debug.result @@ -105,3 +105,58 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; SET DEBUG_SYNC='RESET'; +# +# MDEV-33593: Auto increment deadlock error causes ASSERT in subsequent save point +# +CREATE TABLE t1(col1 INT PRIMARY KEY AUTO_INCREMENT, col2 INT) ENGINE=InnoDB; +CREATE TABLE t2(col1 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1(col2) values(100); +connect con1, localhost, root,,; +START TRANSACTION; +# T1: Acquiring Row X lock on table t2 +INSERT INTO t2 values(100); +connect con2, localhost, root,,; +START TRANSACTION; +# T2: Wait for (T1) row lock on t2 after acquiring GAP Lock on t1 +UPDATE t1 SET col2 = 20 where col1 = 10; +INSERT INTO t2 values(100); +connection default; +# T3: Wait for (T2) II row Lock on t1 after acquiring Auto Increment Lock on t1 +SET DEBUG_SYNC='lock_wait_suspend_thread_enter SIGNAL t3_waiting'; +INSERT INTO t1(col2) SELECT col2 from t1; +connection con1; +SAVEPOINT s1; +SET DEBUG_SYNC='now WAIT_FOR t3_waiting'; +# T1: Wait for (T3) auto increment lock on t1 causing T1 -> T3 -> T2 -> T1 deadlock +SET debug_dbug = '+d,innodb_deadlock_victim_self'; +INSERT INTO t1(col2) VALUES(200); +ERROR HY000: Failed to read auto-increment value from storage engine +# The transaction should have been rolled back +SELECT * FROM t1; +col1 col2 +1 100 +SELECT * FROM t2; +col1 +# Release the previous savepoint using the same name +SAVEPOINT s1; +COMMIT; +connection con2; +COMMIT; +connection default; +COMMIT; +disconnect con1; +disconnect con2; +# Cleanup +SELECT * FROM t1; +col1 col2 +1 100 +2 100 +DROP TABLE t1; +SELECT * FROM t2; +col1 +100 +DROP TABLE t2; +SET DEBUG_SYNC='RESET'; +# +# End of 10.5 tests +# diff --git a/mysql-test/suite/innodb/t/autoinc_debug.test b/mysql-test/suite/innodb/t/autoinc_debug.test index 7722b848c74..80168c9d7e1 100644 --- a/mysql-test/suite/innodb/t/autoinc_debug.test +++ b/mysql-test/suite/innodb/t/autoinc_debug.test @@ -92,3 +92,67 @@ SELECT * FROM t1; SHOW CREATE TABLE t1; DROP TABLE t1; SET DEBUG_SYNC='RESET'; + +--echo # +--echo # MDEV-33593: Auto increment deadlock error causes ASSERT in subsequent save point +--echo # + +CREATE TABLE t1(col1 INT PRIMARY KEY AUTO_INCREMENT, col2 INT) ENGINE=InnoDB; +CREATE TABLE t2(col1 INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1(col2) values(100); + +--connect(con1, localhost, root,,) +START TRANSACTION; +--echo # T1: Acquiring Row X lock on table t2 +INSERT INTO t2 values(100); + +--connect(con2, localhost, root,,) +START TRANSACTION; +--echo # T2: Wait for (T1) row lock on t2 after acquiring GAP Lock on t1 +UPDATE t1 SET col2 = 20 where col1 = 10; +--send INSERT INTO t2 values(100) + +--connection default +--echo # T3: Wait for (T2) II row Lock on t1 after acquiring Auto Increment Lock on t1 +SET DEBUG_SYNC='lock_wait_suspend_thread_enter SIGNAL t3_waiting'; +--send INSERT INTO t1(col2) SELECT col2 from t1 + +--connection con1 +SAVEPOINT s1; +SET DEBUG_SYNC='now WAIT_FOR t3_waiting'; +--echo # T1: Wait for (T3) auto increment lock on t1 causing T1 -> T3 -> T2 -> T1 deadlock +SET debug_dbug = '+d,innodb_deadlock_victim_self'; +--error ER_AUTOINC_READ_FAILED +INSERT INTO t1(col2) VALUES(200); + +--echo # The transaction should have been rolled back +SELECT * FROM t1; +SELECT * FROM t2; + +--echo # Release the previous savepoint using the same name +SAVEPOINT s1; +COMMIT; + +--connection con2 +--reap +COMMIT; + +--connection default +--reap +COMMIT; + +--disconnect con1 +--disconnect con2 + +--echo # Cleanup +SELECT * FROM t1; +DROP TABLE t1; + +SELECT * FROM t2; +DROP TABLE t2; + +SET DEBUG_SYNC='RESET'; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c45b0ad0bbb..ad2e022f0b3 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16655,6 +16655,13 @@ ha_innobase::get_auto_increment( if (error != DB_SUCCESS) { *first_value = (~(ulonglong) 0); + /* This is an error case. We do the error handling by calling + the error code conversion function. Specifically, we need to + call thd_mark_transaction_to_rollback() to inform sql that we + have rolled back innodb transaction after a deadlock error. We + ignore the returned mysql error code here. */ + std::ignore = convert_error_code_to_mysql( + error, m_prebuilt->table->flags, m_user_thd); return; } diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index c781ae23852..0891ad5ceb7 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6712,6 +6712,8 @@ DeadlockChecker::select_victim() const ut_ad(m_start->lock.wait_lock != 0); ut_ad(m_wait_lock->trx != m_start); + DBUG_EXECUTE_IF("innodb_deadlock_victim_self", return m_start;); + if (trx_weight_ge(m_wait_lock->trx, m_start)) { /* The joining transaction is 'smaller', choose it as the victim and roll it back. */