From a31e99a89cc75804c9d118835b39d9780f504312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 May 2018 10:48:48 +0300 Subject: [PATCH 01/12] Remove an unnecessary #include --- storage/innobase/handler/handler0alter.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index d1a68813a29..bc88001edf6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -54,10 +54,6 @@ Smart ALTER TABLE #include "ha_innodb.h" #include "ut0new.h" #include "ut0stage.h" -#ifdef WITH_WSREP -//#include "wsrep_api.h" -#include // PROCESS_ACL -#endif static const char *MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN= "INPLACE ADD or DROP of virtual columns cannot be " From b2f86ebdd254d923daf6f29e64e61e19187044b9 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Thu, 31 May 2018 18:55:07 -0700 Subject: [PATCH 02/12] MDEV-16353 Server crash on query with CTE This bug caused crashes for queries with unreferenced non-recursive CTEs specified by unions.It happened because the function st_select_lex_unit::prepare() tried to use the value of the field 'derived' that could not be set for unferenced CTEs as there was no derived table associated with an unreferenced CTE. --- mysql-test/r/cte_nonrecursive.result | 16 ++++++++++++++++ mysql-test/t/cte_nonrecursive.test | 18 ++++++++++++++++++ sql/sql_union.cc | 2 +- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/cte_nonrecursive.result b/mysql-test/r/cte_nonrecursive.result index 001df909bcf..1d079c3bfa6 100644 --- a/mysql-test/r/cte_nonrecursive.result +++ b/mysql-test/r/cte_nonrecursive.result @@ -1462,3 +1462,19 @@ a b 4 5 4 3 DROP TABLE t1; +# +# MDEV-16353: unreferenced CTE specified by query with UNION +# +with cte as +(select 1 union select 2 union select 3) +select 1 as f; +f +1 +create table t1 (a int); +insert into t1 values (2), (1), (7), (1), (4); +with cte as +(select * from t1 where a < 2 union select * from t1 where a > 5) +select 2 as f; +f +2 +drop table t1; diff --git a/mysql-test/t/cte_nonrecursive.test b/mysql-test/t/cte_nonrecursive.test index 5e1770496f6..98a77940c99 100644 --- a/mysql-test/t/cte_nonrecursive.test +++ b/mysql-test/t/cte_nonrecursive.test @@ -1012,3 +1012,21 @@ SELECT a FROM cte; WITH cte(a,b) AS (SELECT 4,5 UNION SELECT 4,3) SELECT a,b FROM cte; DROP TABLE t1; + +--echo # +--echo # MDEV-16353: unreferenced CTE specified by query with UNION +--echo # + +with cte as + (select 1 union select 2 union select 3) +select 1 as f; + +create table t1 (a int); +insert into t1 values (2), (1), (7), (1), (4); + +with cte as + (select * from t1 where a < 2 union select * from t1 where a > 5) +select 2 as f; + +drop table t1; + \ No newline at end of file diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 13c19dae342..178d7393878 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -625,7 +625,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, { if (with_element) { - if (derived->with->rename_columns_of_derived_unit(thd, this)) + if (with_element->rename_columns_of_derived_unit(thd, this)) goto err; if (check_duplicate_names(thd, sl->item_list, 0)) goto err; From 40dc1a684694f1023c42f46b587d917a9988284a Mon Sep 17 00:00:00 2001 From: gvtek <34262684+gvtek@users.noreply.github.com> Date: Sat, 26 May 2018 16:42:13 -0700 Subject: [PATCH 03/12] Better Link Spacing Just spacing out the links on separate linkes, they were running together in a block of text and could be a little hard for some people to differentiate where one begins and the next ends. Seems silly, but just trying to help in the formatting a bit. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index f46888e4b2f..00587110004 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,15 @@ see the Credits appendix. You can also run 'SHOW authors' to get a list of active contributors. A description of the MariaDB project and a manual can be found at: + https://mariadb.org/ + https://mariadb.com/kb/en/ + https://mariadb.com/kb/en/mariadb-vs-mysql-features/ + https://mariadb.com/kb/en/mariadb-versus-mysql-features/ + https://mariadb.com/kb/en/mariadb-versus-mysql-compatibility/ As MariaDB is a full replacement of MySQL, the MySQL manual at From 898a8c3c0ce2c56773865521c59d5ac172495978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Kek=C3=A4l=C3=A4inen?= Date: Fri, 1 Jun 2018 22:24:20 +0300 Subject: [PATCH 04/12] Deb: Disable PIE in debian/rules on older Debian/Ubuntu releases This partially reverts commit dc0a76600b65950c478782203ac811e7e1027123. --- debian/autobake-deb.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/autobake-deb.sh b/debian/autobake-deb.sh index 48721043279..132bb2eea7b 100755 --- a/debian/autobake-deb.sh +++ b/debian/autobake-deb.sh @@ -81,6 +81,16 @@ then sed '/libzstd1/d' -i debian/control fi +# The binaries should be fully hardened by default. However TokuDB compilation seems to fail on +# Debian Jessie and older and on Ubuntu Xenial and older with the following error message: +# /usr/bin/ld.bfd.real: /tmp/ccOIwjFo.ltrans0.ltrans.o: relocation R_X86_64_PC32 against symbol +# `toku_product_name_strings' can not be used when making a shared object; recompile with -fPIC +# Therefore we need to disable PIE on those releases using debhelper as proxy for detection. +if ! apt-cache madison debhelper | grep 'debhelper *| *1[0-9]\.' >/dev/null 2>&1 +then + sed 's/hardening=+all$/hardening=+all,-pie/' -i debian/rules +fi + # Convert gcc version to numberical value. Format is Mmmpp where M is Major # version, mm is minor version and p is patch. From 486682b1daf8488d93c3763a67671db3a5076d98 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 22 May 2018 21:57:20 +0200 Subject: [PATCH 05/12] cleanup: vers tests, remove create_table procedure --- .../suite/versioning/key_type.combinations | 2 -- mysql-test/suite/versioning/key_type.inc | 23 --------------- mysql-test/suite/versioning/r/replace.result | 26 +++++++++++++++-- mysql-test/suite/versioning/t/replace.test | 29 ++++++++++++++++--- 4 files changed, 48 insertions(+), 32 deletions(-) delete mode 100644 mysql-test/suite/versioning/key_type.combinations delete mode 100644 mysql-test/suite/versioning/key_type.inc diff --git a/mysql-test/suite/versioning/key_type.combinations b/mysql-test/suite/versioning/key_type.combinations deleted file mode 100644 index 1929aee9a84..00000000000 --- a/mysql-test/suite/versioning/key_type.combinations +++ /dev/null @@ -1,2 +0,0 @@ -[unique] -[pk] diff --git a/mysql-test/suite/versioning/key_type.inc b/mysql-test/suite/versioning/key_type.inc deleted file mode 100644 index 648430771cf..00000000000 --- a/mysql-test/suite/versioning/key_type.inc +++ /dev/null @@ -1,23 +0,0 @@ ---disable_query_log -if ($MTR_COMBINATION_UNIQUE) -{ - set @KEY_TYPE= 'unique'; -} -if ($MTR_COMBINATION_PK) -{ - set @KEY_TYPE= 'primary key'; -} - -delimiter ~~; -create procedure create_table(name varchar(255), cols varchar(255)) -begin - if (cols is null or cols = '') then - set cols= ''; - else - set cols= concat(', ', cols); - end if; - set @str= concat('create or replace table ', name, '(id int ', @KEY_TYPE, cols, ') with system versioning'); - prepare stmt from @str; execute stmt; drop prepare stmt; -end~~ -delimiter ;~~ ---enable_query_log diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result index 54ab5b49c2a..a3bd3239a5e 100644 --- a/mysql-test/suite/versioning/r/replace.result +++ b/mysql-test/suite/versioning/r/replace.result @@ -1,4 +1,10 @@ -call create_table('t', 'x int'); +create table t ( +id int primary key, +x int, +row_start SYS_DATATYPE as row start invisible, +row_end SYS_DATATYPE as row end invisible, +period for system_time (row_start, row_end) +) with system versioning; insert t values (1, 2); replace t values (1, 3); select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all @@ -6,5 +12,19 @@ order by x; id x current 1 2 0 1 3 1 -drop database test; -create database test; +drop table t; +create table t ( +id int unique, +x int, +row_start SYS_DATATYPE as row start invisible, +row_end SYS_DATATYPE as row end invisible, +period for system_time (row_start, row_end) +) with system versioning; +insert t values (1, 2); +replace t values (1, 3); +select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all +order by x; +id x current +1 2 0 +1 3 1 +drop table t; diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test index 194606555db..0a100c66607 100644 --- a/mysql-test/suite/versioning/t/replace.test +++ b/mysql-test/suite/versioning/t/replace.test @@ -1,13 +1,34 @@ --source suite/versioning/common.inc ---source suite/versioning/key_type.inc --source suite/versioning/engines.inc -call create_table('t', 'x int'); +--replace_result $sys_datatype_expl SYS_DATATYPE +eval create table t ( + id int primary key, + x int, + row_start $sys_datatype_expl as row start invisible, + row_end $sys_datatype_expl as row end invisible, + period for system_time (row_start, row_end) +) with system versioning; insert t values (1, 2); replace t values (1, 3); select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all order by x; +drop table t; -drop database test; -create database test; +--replace_result $sys_datatype_expl SYS_DATATYPE +eval create table t ( + id int unique, + x int, + row_start $sys_datatype_expl as row start invisible, + row_end $sys_datatype_expl as row end invisible, + period for system_time (row_start, row_end) +) with system versioning; + +insert t values (1, 2); +replace t values (1, 3); +select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all +order by x; +drop table t; + +--source suite/versioning/common_finish.inc From b1efff46cd0c32bd696fb2194306edbdfcd75426 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 26 Feb 2018 19:41:04 +0300 Subject: [PATCH 06/12] Vers cleanups * Always-false vers_select_conds_t::from_query * Debug helpers Closes #684 --- mysql-test/suite/versioning/r/replace.result | 6 ++---- mysql-test/suite/versioning/t/replace.test | 6 ++---- sql/sql_select.cc | 3 +-- sql/sql_yacc.yy | 5 +++-- sql/table.h | 9 ++------- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result index a3bd3239a5e..52db0db429a 100644 --- a/mysql-test/suite/versioning/r/replace.result +++ b/mysql-test/suite/versioning/r/replace.result @@ -7,8 +7,7 @@ period for system_time (row_start, row_end) ) with system versioning; insert t values (1, 2); replace t values (1, 3); -select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all -order by x; +select *, current_row(row_end) as current from t for system_time all order by x; id x current 1 2 0 1 3 1 @@ -22,8 +21,7 @@ period for system_time (row_start, row_end) ) with system versioning; insert t values (1, 2); replace t values (1, 3); -select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all -order by x; +select *, current_row(row_end) as current from t for system_time all order by x; id x current 1 2 0 1 3 1 diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test index 0a100c66607..a4f7b245988 100644 --- a/mysql-test/suite/versioning/t/replace.test +++ b/mysql-test/suite/versioning/t/replace.test @@ -12,8 +12,7 @@ eval create table t ( insert t values (1, 2); replace t values (1, 3); -select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all -order by x; +select *, current_row(row_end) as current from t for system_time all order by x; drop table t; --replace_result $sys_datatype_expl SYS_DATATYPE @@ -27,8 +26,7 @@ eval create table t ( insert t values (1, 2); replace t values (1, 3); -select *, row_end>TIMESTAMP'2038-01-01 00:00:00' as current from t for system_time all -order by x; +select *, current_row(row_end) as current from t for system_time all order by x; drop table t; --source suite/versioning/common_finish.inc diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3dfc41ae86c..99437e52c13 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -678,7 +678,6 @@ bool vers_select_conds_t::init_from_sysvar(THD *thd) vers_asof_timestamp_t &in= thd->variables.vers_asof_timestamp; type= (vers_system_time_t) in.type; start.unit= VERS_TIMESTAMP; - from_query= false; if (type != SYSTEM_TIME_UNSPECIFIED && type != SYSTEM_TIME_ALL) { DBUG_ASSERT(type == SYSTEM_TIME_AS_OF); @@ -741,7 +740,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) { if (table->table && table->table->versioned()) versioned_tables++; - else if (table->vers_conditions.user_defined() && + else if (table->vers_conditions.is_set() && (table->is_non_derived() || !table->vers_conditions.used)) { my_error(ER_VERS_NOT_VERSIONED, MYF(0), table->alias.str); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 049b2c0cac9..b53a89ecc94 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -11788,9 +11788,10 @@ table_primary_ident: pop_index_hints(), $3)))) MYSQL_YYABORT; - Select->add_joined_table($$); + TABLE_LIST *tl= $$; + Select->add_joined_table(tl); if ($4) - $$->vers_conditions= Lex->vers_conditions; + tl->vers_conditions= Lex->vers_conditions; } ; diff --git a/sql/table.h b/sql/table.h index 7b411f00d21..ea00441fb5e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1848,7 +1848,6 @@ public: struct vers_select_conds_t { vers_system_time_t type; - bool from_query:1; bool used:1; Vers_history_point start; Vers_history_point end; @@ -1856,7 +1855,7 @@ struct vers_select_conds_t void empty() { type= SYSTEM_TIME_UNSPECIFIED; - used= from_query= false; + used= false; start.empty(); end.empty(); } @@ -1866,7 +1865,7 @@ struct vers_select_conds_t Vers_history_point _end= Vers_history_point()) { type= _type; - used= from_query= false; + used= false; start= _start; end= _end; } @@ -1880,10 +1879,6 @@ struct vers_select_conds_t return type != SYSTEM_TIME_UNSPECIFIED; } bool resolve_units(THD *thd); - bool user_defined() const - { - return !from_query && type != SYSTEM_TIME_UNSPECIFIED; - } bool eq(const vers_select_conds_t &conds) const; }; From 748ef3ec91d35aa6cd5b230c71084f6c83c1c92e Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 16 May 2018 18:11:30 +0300 Subject: [PATCH 07/12] MDEV-15991 Server crashes in setup_on_expr upon calling SP or function executing DML on versioned tables Do not try to set versioning conditions on every SP call. It may work incorrectly, but it's a general bug described in MDEV-774. This patch makes system versioning stuff consistent with other code and also fixes a use-after-free bug. Closes #756 --- mysql-test/suite/versioning/r/select.result | 21 +++++++++++++++++++++ mysql-test/suite/versioning/t/select.test | 18 ++++++++++++++++++ sql/sql_class.h | 2 -- sql/sql_select.cc | 2 +- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index 80c408980ec..87b8166ef91 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -538,6 +538,27 @@ a select * from t1 for system_time from @t2 to @t1; a drop table t1; +# +# MDEV-15991 Server crashes in setup_on_expr upon calling SP or function executing DML on versioned tables +# +create or replace table t1 (i int); +insert into t1 values (1); +create or replace procedure p(n int) +begin +select * from t1; +end $ +call p(1); +i +1 +alter table t1 add system versioning; +call p(2); +i +1 +call p(3); +i +1 +drop procedure p; +drop table t1; call verify_trt_dummy(34); No A B C D 1 1 1 1 1 diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index bb154f0b248..845cf731af1 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -348,6 +348,24 @@ select * from t1 for system_time from @t1 to @t2; select * from t1 for system_time from @t2 to @t1; drop table t1; +--echo # +--echo # MDEV-15991 Server crashes in setup_on_expr upon calling SP or function executing DML on versioned tables +--echo # +create or replace table t1 (i int); +insert into t1 values (1); +--delimiter $ +create or replace procedure p(n int) +begin + select * from t1; +end $ +--delimiter ; +call p(1); +alter table t1 add system versioning; +call p(2); +call p(3); +drop procedure p; +drop table t1; + call verify_trt_dummy(34); -- source suite/versioning/common_finish.inc diff --git a/sql/sql_class.h b/sql/sql_class.h index 64b75dbe7be..5adb5bf3823 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1007,8 +1007,6 @@ public: { return state == STMT_PREPARED || state == STMT_EXECUTED; } inline bool is_conventional() const { return state == STMT_CONVENTIONAL_EXECUTION; } - inline bool is_sp_execute() const - { return is_stored_procedure; } inline void* alloc(size_t size) { return alloc_root(mem_root,size); } inline void* calloc(size_t size) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 99437e52c13..215803c2637 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -725,7 +725,7 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables) TABLE_LIST *table; if (!thd->stmt_arena->is_conventional() && - !thd->stmt_arena->is_stmt_prepare() && !thd->stmt_arena->is_sp_execute()) + !thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) { // statement is already prepared DBUG_RETURN(0); From eb76698300c8611eddc2756aa5dbc57cdae2e21d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 2 Jun 2018 22:27:59 +0200 Subject: [PATCH 08/12] client.c: set connect attributes as late as possible just before they're sent to the client. Because mysql->host value is known only after the connection is established, and it's needed for the "_sever_host" attribute. This fixes ASAN use-after-free warning in rpl tests followup for ee8dfc688e8 --- sql-common/client.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sql-common/client.c b/sql-common/client.c index 6a44a2db0aa..ad85738b0cb 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -3123,9 +3123,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, DBUG_RETURN(0); } - if (set_connect_attributes(mysql, buff, sizeof(buff))) - DBUG_RETURN(0); - mysql->methods= &client_methods; mysql->client_flag=0; /* For handshake */ @@ -3579,6 +3576,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user, mysql->client_flag= client_flag; + set_connect_attributes(mysql, buff, sizeof(buff)); + /* Part 2: invoke the plugin to send the authentication data to the server */ From cac41001864ca503a7812b7f2a3b312435fb4ec4 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 29 May 2018 16:49:48 +0200 Subject: [PATCH 09/12] cmake: shut up repeated NUMA status messages --- cmake/numa.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/numa.cmake b/cmake/numa.cmake index cdc31229da8..d24318634c3 100644 --- a/cmake/numa.cmake +++ b/cmake/numa.cmake @@ -3,7 +3,7 @@ MACRO (MYSQL_CHECK_NUMA) STRING(TOLOWER "${WITH_NUMA}" WITH_NUMA_LOWERCASE) IF(NOT WITH_NUMA) - MESSAGE(STATUS "WITH_NUMA=OFF: NUMA memory allocation policy disabled") + MESSAGE_ONCE(numa "WITH_NUMA=OFF: NUMA memory allocation policy disabled") ELSEIF(NOT WITH_NUMA_LOWERCASE STREQUAL "auto" AND NOT WITH_NUMA_LOWERCASE STREQUAL "on") MESSAGE(FATAL_ERROR "Wrong value for WITH_NUMA") @@ -34,11 +34,11 @@ MACRO (MYSQL_CHECK_NUMA) ENDIF() IF(WITH_NUMA_LOWERCASE STREQUAL "auto" AND HAVE_LIBNUMA) - MESSAGE(STATUS "WITH_NUMA=AUTO: NUMA memory allocation policy enabled") + MESSAGE_ONCE(numa "WITH_NUMA=AUTO: NUMA memory allocation policy enabled") ELSEIF(WITH_NUMA_LOWERCASE STREQUAL "auto" AND NOT HAVE_LIBNUMA) - MESSAGE(STATUS "WITH_NUMA=AUTO: NUMA memory allocation policy disabled") + MESSAGE_ONCE(numa "WITH_NUMA=AUTO: NUMA memory allocation policy disabled") ELSEIF(HAVE_LIBNUMA) - MESSAGE(STATUS "WITH_NUMA=ON: NUMA memory allocation policy enabled") + MESSAGE_ONCE(numa "WITH_NUMA=ON: NUMA memory allocation policy enabled") ELSE() # Forget it in cache, abort the build. UNSET(WITH_NUMA CACHE) From 5932a4e77de93880d06ac537a566a8a0f312d675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 4 Jun 2018 11:31:39 +0300 Subject: [PATCH 10/12] MDEV-13834: Upgrade failure from 10.1 innodb_encrypt_log log_crypt_101_read_block(): Mimic MariaDB 10.1, and use the first encryption key if the key for the checkpoint cannot be found. Redo log encryption key rotation was ultimately disabled in MDEV-9422 (MariaDB 10.1.13) due to design issues. So, from MariaDB 10.1.13 onwards only one log encryption key should matter. recv_log_format_0_recover(): Add the parameter 'bool crypt'. Indicate when the log cannot be decrypted for upgrade, instead of making a possibly false claim that the log requires crash recovery. init_crypt_key(): Remove extra space from a message. --- storage/innobase/log/log0crypt.cc | 11 ++++++++--- storage/innobase/log/log0recv.cc | 16 +++++++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc index 0358057612d..478f021cbe4 100644 --- a/storage/innobase/log/log0crypt.cc +++ b/storage/innobase/log/log0crypt.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. -Copyright (C) 2014, 2017, MariaDB Corporation. All Rights Reserved. +Copyright (C) 2014, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -159,7 +159,7 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false) << "Obtaining redo log encryption key version " << info->key_version << " failed (" << rc << "). Maybe the key or the required encryption " - << " key management plugin was not found."; + "key management plugin was not found."; return false; } @@ -279,7 +279,12 @@ log_crypt_101_read_block(byte* buf) } } - return false; + if (infos_used == 0) { + return false; + } + /* MariaDB Server 10.1 would use the first key if it fails to + find a key for the current checkpoint. */ + info = infos; found: byte dst[OS_FILE_LOG_BLOCK_SIZE]; uint dst_len; diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 59f8595c2c4..b7ab1311cb7 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -871,12 +871,11 @@ recv_find_max_checkpoint_0(log_group_t** max_group, ulint* max_field) /** Determine if a pre-MySQL 5.7.9/MariaDB 10.2.2 redo log is clean. @param[in] lsn checkpoint LSN +@param[in] crypt whether the log might be encrypted @return error code @retval DB_SUCCESS if the redo log is clean @retval DB_ERROR if the redo log is corrupted or dirty */ -static -dberr_t -recv_log_format_0_recover(lsn_t lsn) +static dberr_t recv_log_format_0_recover(lsn_t lsn, bool crypt) { log_mutex_enter(); log_group_t* group = &log_sys->log; @@ -911,7 +910,13 @@ recv_log_format_0_recover(lsn_t lsn) } if (log_block_get_data_len(buf) - != (source_offset & (OS_FILE_LOG_BLOCK_SIZE - 1))) { + == (source_offset & (OS_FILE_LOG_BLOCK_SIZE - 1))) { + } else if (crypt) { + ib::error() << "Cannot decrypt log for upgrading." + " The encrypted log was created before MariaDB 10.2.2" + << NO_UPGRADE_RTFM_MSG; + return DB_ERROR; + } else { ib::error() << NO_UPGRADE_RECOVERY_MSG << NO_UPGRADE_RTFM_MSG; return(DB_ERROR); @@ -3259,7 +3264,8 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) switch (group->format) { case 0: log_mutex_exit(); - return(recv_log_format_0_recover(checkpoint_lsn)); + return recv_log_format_0_recover(checkpoint_lsn, + buf[20 + 32 * 9] == 2); default: if (end_lsn == 0) { break; From 8dc70c862b8ec115fd9a3c2b37c746ffc4f0d3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 4 Jun 2018 15:55:37 +0300 Subject: [PATCH 11/12] MDEV-16376 ASAN: heap-use-after-free in gcol.innodb_virtual_debug After a failed ADD INDEX, dict_index_remove_from_cache_low() could iterate the index fields and dereference a freed virtual column object when trying to remove the index from the v_indexes of the virtual column. This regression was caused by a merge of MDEV-16119 InnoDB lock->index refers to a freed object. ha_innobase_inplace_ctx::clear_added_indexes(): Detach the indexes of uncommitted indexes from virtual columns, so that the iteration in dict_index_remove_from_cache_low() can be avoided. ha_innobase::prepare_inplace_alter_table(): Ignore uncommitted corrupted indexes when rejecting ALTER TABLE. (This minor bug was revealed by the extension of the test case.) dict_index_t::detach_columns(): Detach an index from virtual columns. Invoked by both dict_index_remove_from_cache_low() and ha_innobase_inplace_ctx::clear_added_indexes(). dict_col_t::detach(const dict_index_t& index): Detach an index from a column. dict_col_t::is_virtual(): Replaces dict_col_is_virtual(). dict_index_t::has_virtual(): Replaces dict_index_has_virtual(). --- .../suite/gcol/r/innodb_virtual_debug.result | 14 +++++-- .../suite/gcol/t/innodb_virtual_debug.test | 15 +++++-- storage/innobase/dict/dict0dict.cc | 32 +------------- storage/innobase/handler/handler0alter.cc | 14 ++++++- storage/innobase/include/dict0dict.h | 19 +++------ storage/innobase/include/dict0dict.ic | 24 ----------- storage/innobase/include/dict0mem.h | 42 +++++++++++++++++++ storage/innobase/row/row0upd.cc | 2 +- 8 files changed, 85 insertions(+), 77 deletions(-) diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug.result b/mysql-test/suite/gcol/r/innodb_virtual_debug.result index 7774c6c347c..50b714566d9 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug.result @@ -64,11 +64,19 @@ INSERT INTO t VALUES (18, 1, DEFAULT, 'mm'); INSERT INTO t VALUES (28, 1, DEFAULT, 'mm'); INSERT INTO t VALUES (null, null, DEFAULT, 'mm'); CREATE INDEX idx_1 on t(c); -SET SESSION debug_dbug="+d,create_index_fail"; -ALTER TABLE t ADD COLUMN x INT GENERATED ALWAYS AS(a+b), ADD INDEX idx (x); +SET @saved_dbug = @@SESSION.debug_dbug; +SET debug_dbug = '+d,create_index_fail'; +ALTER TABLE t ADD COLUMN x INT GENERATED ALWAYS AS(a+b), ADD INDEX idx (x), +ADD INDEX idcx (c,x); ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' -SET SESSION debug_dbug=""; +UPDATE t SET a=a+1; +affected rows: 3 +info: Rows matched: 4 Changed: 3 Warnings: 0 +ALTER TABLE t ADD INDEX idc(c); +ERROR 23000: Duplicate entry '' for key '*UNKNOWN*' +SET debug_dbug = @saved_dbug; affected rows: 0 +UPDATE t SET b=b-1; SHOW CREATE TABLE t; Table Create Table t CREATE TABLE `t` ( diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug.test b/mysql-test/suite/gcol/t/innodb_virtual_debug.test index 3870f84e066..ccdd16c9ebe 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug.test @@ -119,14 +119,23 @@ INSERT INTO t VALUES (null, null, DEFAULT, 'mm'); CREATE INDEX idx_1 on t(c); -SET SESSION debug_dbug="+d,create_index_fail"; +SET @saved_dbug = @@SESSION.debug_dbug; +SET debug_dbug = '+d,create_index_fail'; --enable_info --error ER_DUP_ENTRY -ALTER TABLE t ADD COLUMN x INT GENERATED ALWAYS AS(a+b), ADD INDEX idx (x); -SET SESSION debug_dbug=""; +ALTER TABLE t ADD COLUMN x INT GENERATED ALWAYS AS(a+b), ADD INDEX idx (x), +ADD INDEX idcx (c,x); + +UPDATE t SET a=a+1; + +--error ER_DUP_ENTRY +ALTER TABLE t ADD INDEX idc(c); +SET debug_dbug = @saved_dbug; --disable_info +UPDATE t SET b=b-1; + SHOW CREATE TABLE t; SELECT c FROM t; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 9a7d9eef092..f34da118a31 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -2676,37 +2676,7 @@ dict_index_remove_from_cache_low( UT_LIST_REMOVE(table->indexes, index); /* Remove the index from affected virtual column index list */ - if (dict_index_has_virtual(index)) { - const dict_col_t* col; - const dict_v_col_t* vcol; - - for (ulint i = 0; i < dict_index_get_n_fields(index); i++) { - col = dict_index_get_nth_col(index, i); - if (dict_col_is_virtual(col)) { - vcol = reinterpret_cast( - col); - - /* This could be NULL, when we do add virtual - column, add index together. We do not need to - track this virtual column's index */ - if (vcol->v_indexes == NULL) { - continue; - } - - dict_v_idx_list::iterator it; - - for (it = vcol->v_indexes->begin(); - it != vcol->v_indexes->end(); ++it) { - dict_v_idx_t v_index = *it; - if (v_index.index == index) { - vcol->v_indexes->erase(it); - break; - } - } - } - - } - } + index->detach_columns(); dict_mem_index_free(index); } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index bc88001edf6..517f20006af 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -245,6 +245,16 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx @return whether the table will be rebuilt */ bool need_rebuild () const { return(old_table != new_table); } + /** Clear uncommmitted added indexes after a failed operation. */ + void clear_added_indexes() + { + for (ulint i = 0; i < num_to_add_index; i++) { + if (!add_index[i]->is_committed()) { + add_index[i]->detach_columns(); + } + } + } + private: // Disable copying ha_innobase_inplace_ctx(const ha_innobase_inplace_ctx&); @@ -5996,7 +6006,8 @@ check_if_can_drop_indexes: for (dict_index_t* index = dict_table_get_first_index(indexed_table); index != NULL; index = dict_table_get_next_index(index)) { - if (!index->to_be_dropped && index->is_corrupted()) { + if (!index->to_be_dropped && index->is_committed() + && index->is_corrupted()) { my_error(ER_INDEX_CORRUPT, MYF(0), index->name()); goto err_exit; } @@ -6567,6 +6578,7 @@ oom: that we hold at most a shared lock on the table. */ m_prebuilt->trx->error_info = NULL; ctx->trx->error_state = DB_SUCCESS; + ctx->clear_added_indexes(); DBUG_RETURN(true); } diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 51ce248b98d..9822b57d190 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -750,13 +750,9 @@ dict_index_is_spatial( /*==================*/ const dict_index_t* index) /*!< in: index */ MY_ATTRIBUTE((warn_unused_result)); -/** Check whether the index contains a virtual column. -@param[in] index index -@return nonzero for index on virtual column, zero for other indexes */ -UNIV_INLINE -ulint -dict_index_has_virtual( - const dict_index_t* index); + +#define dict_index_has_virtual(index) (index)->has_virtual() + /********************************************************************//** Check whether the index is the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ @@ -1964,13 +1960,8 @@ dict_index_node_ptr_max_size( /*=========================*/ const dict_index_t* index) /*!< in: index */ MY_ATTRIBUTE((warn_unused_result)); -/** Check if a column is a virtual column -@param[in] col column -@return true if it is a virtual column, false otherwise */ -UNIV_INLINE -bool -dict_col_is_virtual( - const dict_col_t* col); + +#define dict_col_is_virtual(col) (col)->is_virtual() /** encode number of columns and number of virtual columns in one 4 bytes value. We could do this because the number of columns in diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index e20da7c708a..ca2ea769612 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -72,16 +72,6 @@ dict_col_copy_type( type->mbminlen = col->mbminlen; type->mbmaxlen = col->mbmaxlen; } -/** Check if a column is a virtual column -@param[in] col column -@return true if it is a virtual column, false otherwise */ -UNIV_INLINE -bool -dict_col_is_virtual( - const dict_col_t* col) -{ - return(col->prtype & DATA_VIRTUAL); -} #ifdef UNIV_DEBUG /*********************************************************************//** @@ -325,20 +315,6 @@ dict_index_is_spatial( return(index->type & DICT_SPATIAL); } -/** Check whether the index contains a virtual column -@param[in] index index -@return nonzero for the index has virtual column, zero for other indexes */ -UNIV_INLINE -ulint -dict_index_has_virtual( - const dict_index_t* index) -{ - ut_ad(index); - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - return(index->type & DICT_VIRTUAL); -} - /********************************************************************//** Check whether the index is the insert buffer tree. @return nonzero for insert buffer, zero for other indexes */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 18e600c25d3..a18d6c1abdd 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -612,6 +612,13 @@ struct dict_col_t{ unsigned max_prefix:12; /*!< maximum index prefix length on this column. Our current max limit is 3072 for Barracuda table */ + + /** @return whether this is a virtual column */ + bool is_virtual() const { return prtype & DATA_VIRTUAL; } + + /** Detach the column from an index. + @param[in] index index to be detached from */ + inline void detach(const dict_index_t& index); }; /** Index information put in a list of virtual column structure. Index @@ -981,10 +988,45 @@ struct dict_index_t{ return DICT_CLUSTERED == (type & (DICT_CLUSTERED | DICT_IBUF)); } + /** @return whether the index includes virtual columns */ + bool has_virtual() const { return type & DICT_VIRTUAL; } + /** @return whether the index is corrupted */ inline bool is_corrupted() const; + + /** Detach the columns from the index that is to be freed. */ + void detach_columns() + { + if (has_virtual()) { + for (unsigned i = 0; i < n_fields; i++) { + fields[i].col->detach(*this); + } + + n_fields = 0; + } + } }; +/** Detach a column from an index. +@param[in] index index to be detached from */ +inline void dict_col_t::detach(const dict_index_t& index) +{ + if (!is_virtual()) { + return; + } + + if (dict_v_idx_list* v_indexes = reinterpret_cast + (this)->v_indexes) { + for (dict_v_idx_list::iterator i = v_indexes->begin(); + i != v_indexes->end(); i++) { + if (i->index == &index) { + v_indexes->erase(i); + return; + } + } + } +} + /** The status of online index creation */ enum online_index_status { /** the index is complete and ready for access */ diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 946bbae9534..18a6a26f3ce 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -593,7 +593,7 @@ row_upd_changes_field_size_or_external( /* We should ignore virtual field if the index is not a virtual index */ if (upd_fld_is_virtual_col(upd_field) - && dict_index_has_virtual(index) != DICT_VIRTUAL) { + && !index->has_virtual()) { continue; } From 106f0b5798a2b5d13b7d67c3cc678fc0cc2184c2 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 5 Jun 2018 10:25:39 +0400 Subject: [PATCH 12/12] MDEV-16385 ROW SP variable is allowed in unexpected context The problem described in the bug report happened because the code did not test check_cols(1) after fix_fields() in a few places. Additionally, fix_fields() could be called multiple times for SP variables, because they are all fixed at a early stage in append_for_log(). Solution: 1. Adding a few helper methods - fix_fields_if_needed() - fix_fields_if_needed_for_scalar() - fix_fields_if_needed_for_bool() - fix_fields_if_needed_for_order_by() and using it in many cases instead of fix_fields() where the "fixed" status is not definitely known to be "false". 2. Adding DBUG_ASSERT(!fixed) into Item_splocal*::fix_fields() to catch double execution. 3. Adding tests. As a good side effect, the patch removes a lot of duplicate code (~60 lines): if (!item->fixed && item->fix_fields(..) && item->check_cols(1)) return true; --- mysql-test/main/sp-row.result | 25 +++++++++++++++++++++++++ mysql-test/main/sp-row.test | 35 +++++++++++++++++++++++++++++++++++ sql/item.cc | 24 +++++++++--------------- sql/item.h | 23 +++++++++++++++++++---- sql/item_cmpfunc.cc | 12 +++++------- sql/item_func.cc | 9 +++------ sql/item_row.cc | 3 +-- sql/item_subselect.cc | 18 ++++++++---------- sql/item_sum.cc | 13 ++++--------- sql/item_windowfunc.cc | 4 +--- sql/opt_subselect.cc | 24 +++++++++--------------- sql/set_var.cc | 6 ++---- sql/sp_head.cc | 10 ++++------ sql/sql_analyse.cc | 4 ++-- sql/sql_base.cc | 17 +++++++---------- sql/sql_derived.cc | 4 +--- sql/sql_get_diagnostics.cc | 3 +-- sql/sql_handler.cc | 8 +++----- sql/sql_help.cc | 3 +-- sql/sql_insert.cc | 2 +- sql/sql_lex.cc | 24 ++++++------------------ sql/sql_lex.h | 2 +- sql/sql_parse.cc | 8 +++----- sql/sql_partition.cc | 4 ++-- sql/sql_prepare.cc | 6 ++---- sql/sql_select.cc | 29 +++++++++++++---------------- sql/sql_show.cc | 7 ++----- sql/sql_signal.cc | 13 +++---------- sql/sql_trigger.cc | 3 +-- sql/sql_view.cc | 2 +- sql/table.cc | 20 +++++++------------- sql/unireg.cc | 5 ++--- 32 files changed, 184 insertions(+), 186 deletions(-) diff --git a/mysql-test/main/sp-row.result b/mysql-test/main/sp-row.result index ac09f7572c3..da8258d9ec4 100644 --- a/mysql-test/main/sp-row.result +++ b/mysql-test/main/sp-row.result @@ -2281,3 +2281,28 @@ t1 CREATE TABLE `t1` ( `int11` int(11) DEFAULT NULL, `text1` text DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 +# +# MDEV-16385 ROW SP variable is allowed in unexpected context +# +CREATE TABLE t1 (a INT); +BEGIN NOT ATOMIC +DECLARE row ROW(a INT); +SELECT * FROM t1 ORDER BY row; +END; +$$ +ERROR 21000: Operand should contain 1 column(s) +DROP TABLE t1; +CREATE TABLE t1 (a INT); +BEGIN NOT ATOMIC +DECLARE row ROW(a INT); +SELECT * FROM t1 HAVING row; +END; +$$ +ERROR 21000: Operand should contain 1 column(s) +DROP TABLE t1; +BEGIN NOT ATOMIC +DECLARE a ROW(a INT); +SELECT 1 LIKE 2 ESCAPE a; +END; +$$ +ERROR 21000: Operand should contain 1 column(s) diff --git a/mysql-test/main/sp-row.test b/mysql-test/main/sp-row.test index 837e24c89c0..3352c940cb6 100644 --- a/mysql-test/main/sp-row.test +++ b/mysql-test/main/sp-row.test @@ -1504,3 +1504,38 @@ BEGIN NOT ATOMIC END; $$ DELIMITER ;$$ + +--echo # +--echo # MDEV-16385 ROW SP variable is allowed in unexpected context +--echo # + +CREATE TABLE t1 (a INT); +DELIMITER $$; +--error ER_OPERAND_COLUMNS +BEGIN NOT ATOMIC + DECLARE row ROW(a INT); + SELECT * FROM t1 ORDER BY row; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; + +CREATE TABLE t1 (a INT); +DELIMITER $$; +--error ER_OPERAND_COLUMNS +BEGIN NOT ATOMIC + DECLARE row ROW(a INT); + SELECT * FROM t1 HAVING row; +END; +$$ +DELIMITER ;$$ +DROP TABLE t1; + +DELIMITER $$; +--error ER_OPERAND_COLUMNS +BEGIN NOT ATOMIC + DECLARE a ROW(a INT); + SELECT 1 LIKE 2 ESCAPE a; +END; +$$ +DELIMITER ;$$ diff --git a/sql/item.cc b/sql/item.cc index 8fae773f487..dac68d1a4c7 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1827,6 +1827,7 @@ Item_field *Item_splocal::get_variable(sp_rcontext *ctx) const bool Item_splocal::fix_fields(THD *thd, Item **ref) { + DBUG_ASSERT(!fixed); Item *item= get_variable(thd->spcont); set_handler(item->type_handler()); return fix_fields_from_item(thd, ref, item); @@ -1954,6 +1955,7 @@ bool Item_splocal::check_cols(uint n) bool Item_splocal_row_field::fix_fields(THD *thd, Item **ref) { + DBUG_ASSERT(!fixed); Item *item= get_variable(thd->spcont)->element_index(m_field_idx); return fix_fields_from_item(thd, ref, item); } @@ -2011,6 +2013,7 @@ bool Item_splocal_row_field::set_value(THD *thd, sp_rcontext *ctx, Item **it) bool Item_splocal_row_field_by_name::fix_fields(THD *thd, Item **it) { + DBUG_ASSERT(!fixed); m_thd= thd; if (get_rcontext(thd->spcont)->find_row_field_by_name_or_error(&m_field_idx, m_var_idx, @@ -2231,10 +2234,8 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) String s(buf, sizeof(buf), &my_charset_bin); s.length(0); - if ((!value_item->fixed && - value_item->fix_fields(thd, &value_item)) || - (!name_item->fixed && - name_item->fix_fields(thd, &name_item)) || + if (value_item->fix_fields_if_needed(thd, &value_item) || + name_item->fix_fields_if_needed(thd, &name_item) || !value_item->const_item() || !name_item->const_item() || !(item_name= name_item->val_str(&s))) // Can't have a NULL name @@ -9022,8 +9023,7 @@ bool Item_direct_view_ref::fix_fields(THD *thd, Item **reference) bitmap_set_bit(fld->table->read_set, fld->field_index); } } - else if (!(*ref)->fixed && - ((*ref)->fix_fields(thd, ref))) + else if ((*ref)->fix_fields_if_needed(thd, ref)) return TRUE; if (Item_direct_ref::fix_fields(thd, reference)) @@ -9051,7 +9051,7 @@ bool Item_outer_ref::fix_fields(THD *thd, Item **reference) { bool err; /* outer_ref->check_cols() will be made in Item_direct_ref::fix_fields */ - if ((*ref) && !(*ref)->fixed && ((*ref)->fix_fields(thd, reference))) + if ((*ref) && (*ref)->fix_fields_if_needed(thd, reference)) return TRUE; err= Item_direct_ref::fix_fields(thd, reference); if (!outer_ref) @@ -9290,7 +9290,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) fixed= 1; return FALSE; } - if (!arg->fixed && arg->fix_fields(thd, &arg)) + if (arg->fix_fields_if_needed(thd, &arg)) goto error; @@ -9635,15 +9635,9 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it) { Item *item= thd->sp_prepare_func_item(it); - if (!item) + if (!item || fix_fields_if_needed(thd, NULL)) return true; - if (!fixed) - { - if (fix_fields(thd, NULL)) - return true; - } - // NOTE: field->table->copy_blobs should be false here, but let's // remember the value at runtime to avoid subtle bugs. bool copy_blobs_saved= field->table->copy_blobs; diff --git a/sql/item.h b/sql/item.h index dcbe41de97f..10ce987e289 100644 --- a/sql/item.h +++ b/sql/item.h @@ -816,6 +816,23 @@ public: void init_make_send_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); virtual void make_send_field(THD *thd, Send_field *field); + + bool fix_fields_if_needed(THD *thd, Item **ref) + { + return fixed ? false : fix_fields(thd, ref); + } + bool fix_fields_if_needed_for_scalar(THD *thd, Item **ref) + { + return fix_fields_if_needed(thd, ref) || check_cols(1); + } + bool fix_fields_if_needed_for_bool(THD *thd, Item **ref) + { + return fix_fields_if_needed_for_scalar(thd, ref); + } + bool fix_fields_if_needed_for_order_by(THD *thd, Item **ref) + { + return fix_fields_if_needed_for_scalar(thd, ref); + } virtual bool fix_fields(THD *, Item **); /* Fix after some tables has been pulled out. Basically re-calculate all @@ -4941,8 +4958,7 @@ public: bool fix_fields(THD *thd, Item **it) { - if ((!(*ref)->fixed && (*ref)->fix_fields(thd, ref)) || - (*ref)->check_cols(1)) + if ((*ref)->fix_fields_if_needed_for_scalar(thd, ref)) return TRUE; return Item_ref::fix_fields(thd, it); } @@ -4980,8 +4996,7 @@ public: bool fix_fields(THD *thd, Item **it) { DBUG_ASSERT(ident->type() == FIELD_ITEM || ident->type() == REF_ITEM); - if ((!ident->fixed && ident->fix_fields(thd, ref)) || - ident->check_cols(1)) + if (ident->fix_fields_if_needed_for_scalar(thd, ref)) return TRUE; set_properties(); return FALSE; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 76f4788c1cf..3034636dca3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1242,7 +1242,7 @@ bool Item_in_optimizer::fix_left(THD *thd) ref0= &(((Item_in_subselect *)args[1])->left_expr); args[0]= ((Item_in_subselect *)args[1])->left_expr; } - if ((!(*ref0)->fixed && (*ref0)->fix_fields(thd, ref0)) || + if ((*ref0)->fix_fields_if_needed(thd, ref0) || (!cache && !(cache= (*ref0)->get_cache(thd)))) DBUG_RETURN(1); /* @@ -1327,7 +1327,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, Item **ref) if (args[0]->maybe_null) maybe_null=1; - if (!args[1]->fixed && args[1]->fix_fields(thd, args+1)) + if (args[1]->fix_fields_if_needed(thd, args + 1)) return TRUE; if (!invisible_mode() && ((sub && ((col= args[0]->cols()) != sub->engine->cols())) || @@ -4586,11 +4586,9 @@ Item_cond::fix_fields(THD *thd, Item **ref) thd->restore_active_arena(arena, &backup); } - // item can be substituted in fix_fields - if ((!item->fixed && - item->fix_fields(thd, li.ref())) || - (item= *li.ref())->check_cols(1)) + if (item->fix_fields_if_needed_for_bool(thd, li.ref())) return TRUE; /* purecov: inspected */ + item= *li.ref(); // item can be substituted in fix_fields used_tables_cache|= item->used_tables(); if (item->const_item() && !item->with_param && !item->is_expensive() && !cond_has_datetime_is_null(item)) @@ -5306,7 +5304,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); if (Item_bool_func2::fix_fields(thd, ref) || - escape_item->fix_fields(thd, &escape_item) || + escape_item->fix_fields_if_needed_for_scalar(thd, &escape_item) || fix_escape_item(thd, escape_item, &cmp_value1, escape_used_in_parsing, cmp_collation.collation, &escape)) return TRUE; diff --git a/sql/item_func.cc b/sql/item_func.cc index c291e897957..567c813de3c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -360,7 +360,7 @@ Item_func::fix_fields(THD *thd, Item **ref) We can't yet set item to *arg as fix_fields may change *arg We shouldn't call fix_fields() twice, so check 'fixed' field first */ - if ((!(*arg)->fixed && (*arg)->fix_fields(thd, arg))) + if ((*arg)->fix_fields_if_needed(thd, arg)) return TRUE; /* purecov: inspected */ item= *arg; @@ -3279,13 +3279,10 @@ udf_handler::fix_fields(THD *thd, Item_func_or_sum *func, arg != arg_end ; arg++,i++) { - if (!(*arg)->fixed && - (*arg)->fix_fields(thd, arg)) - DBUG_RETURN(1); + if ((*arg)->fix_fields_if_needed_for_scalar(thd, arg)) + DBUG_RETURN(true); // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; - if (item->check_cols(1)) - DBUG_RETURN(TRUE); /* TODO: We should think about this. It is not always right way just to set an UDF result to return my_charset_bin diff --git a/sql/item_row.cc b/sql/item_row.cc index 74ea9ecc0c2..8233ba00f06 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -41,8 +41,7 @@ bool Item_row::fix_fields(THD *thd, Item **ref) Item **arg, **arg_end; for (arg= args, arg_end= args + arg_count; arg != arg_end ; arg++) { - if (!(*arg)->fixed && - (*arg)->fix_fields(thd, arg)) + if ((*arg)->fix_fields_if_needed(thd, arg)) return TRUE; // we can't assign 'item' before, because fix_fields() can change arg Item *item= *arg; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 143894ad949..4280a67e356 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -302,8 +302,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref) engine->exclude(); substitution= 0; thd->where= "checking transformed subquery"; - if (!(*ref)->fixed) - res= (*ref)->fix_fields(thd, ref); + res= (*ref)->fix_fields_if_needed(thd, ref); goto end; } @@ -2181,7 +2180,7 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join, row_value_transformer? */ item->name= in_additional_cond; - if (!item->fixed && item->fix_fields(thd, 0)) + if (item->fix_fields_if_needed(thd, 0)) DBUG_RETURN(true); *where_item= item; } @@ -2504,7 +2503,7 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join, if (*where_item) { - if (!(*where_item)->fixed && (*where_item)->fix_fields(thd, 0)) + if ((*where_item)->fix_fields_if_needed(thd, 0)) DBUG_RETURN(true); (*where_item)->top_level_item(); } @@ -2651,7 +2650,7 @@ bool Item_in_subselect::inject_in_to_exists_cond(JOIN *join_arg) } where_item= and_items(thd, join_arg->conds, where_item); - if (!where_item->fixed && where_item->fix_fields(thd, 0)) + if (where_item->fix_fields_if_needed(thd, 0)) DBUG_RETURN(true); // TIMOUR TODO: call optimize_cond() for the new where clause thd->change_item_tree(&select_lex->where, where_item); @@ -3117,7 +3116,7 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg) exp= optimizer; } upper_not->arguments()[0]= exp; - if (!exp->fixed && exp->fix_fields(thd, upper_not->arguments())) + if (exp->fix_fields_if_needed(thd, upper_not->arguments())) { res= TRUE; goto out; @@ -3315,8 +3314,7 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) } } - if (left_expr && !left_expr->fixed && - left_expr->fix_fields(thd_arg, &left_expr)) + if (left_expr && left_expr->fix_fields_if_needed(thd_arg, &left_expr)) goto err; else if (Item_subselect::fix_fields(thd_arg, ref)) @@ -4999,8 +4997,8 @@ bool subselect_hash_sj_engine::init(List *tmp_columns, uint subquery_id) Repeat name resolution for 'cond' since cond is not part of any clause of the query, and it is not 'fixed' during JOIN::prepare. */ - if (semi_join_conds && !semi_join_conds->fixed && - semi_join_conds->fix_fields(thd, (Item**)&semi_join_conds)) + if (semi_join_conds && + semi_join_conds->fix_fields_if_needed(thd, (Item**)&semi_join_conds)) DBUG_RETURN(TRUE); /* Let our engine reuse this query plan for materialization. */ materialize_join= materialize_engine->join; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5c2f8ab27b7..a47f3ad941d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1129,7 +1129,7 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) maybe_null= sum_func() != COUNT_FUNC; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) return TRUE; set_if_bigger(decimals, args[i]->decimals); m_with_subquery|= args[i]->with_subquery(); @@ -1156,14 +1156,11 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) DBUG_ENTER("Item_sum_hybrid::fix_fields"); DBUG_ASSERT(fixed == 0); - Item *item= args[0]; - if (init_sum_func_check(thd)) DBUG_RETURN(TRUE); // 'item' can be changed during fix_fields - if ((!item->fixed && item->fix_fields(thd, args)) || - (item= args[0])->check_cols(1)) + if (args[0]->fix_fields_if_needed_for_scalar(thd, &args[0])) DBUG_RETURN(TRUE); m_with_subquery= args[0]->with_subquery(); @@ -1298,7 +1295,7 @@ Item_sum_sp::fix_fields(THD *thd, Item **ref) for (uint i= 0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd, args + i) || args[i]->check_cols(1)) + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) return TRUE; set_if_bigger(decimals, args[i]->decimals); m_with_subquery|= args[i]->with_subquery(); @@ -3909,9 +3906,7 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) for (i=0 ; i < arg_count ; i++) { - if ((!args[i]->fixed && - args[i]->fix_fields(thd, args + i)) || - args[i]->check_cols(1)) + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) return TRUE; m_with_subquery|= args[i]->with_subquery(); with_param|= args[i]->with_param; diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 85ca8b0624e..a7f8ef09f08 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -327,10 +327,8 @@ bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref) for (uint i= 0; i < arg_count; i++) { - Item *item= args[i]; // 'item' can be changed during fix_fields - if ((!item->fixed && item->fix_fields(thd, args)) || - (item= args[i])->check_cols(1)) + if (args[i]->fix_fields_if_needed_for_scalar(thd, &args[i])) return TRUE; } Type_std_attributes::set(args[0]); diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc index a04a67c9a3f..1cfdcc9c9b2 100644 --- a/sql/opt_subselect.cc +++ b/sql/opt_subselect.cc @@ -620,8 +620,8 @@ int check_and_do_in_subquery_rewrites(JOIN *join) char const *save_where= thd->where; thd->where= "IN/ALL/ANY subquery"; - bool failure= !in_subs->left_expr->fixed && - in_subs->left_expr->fix_fields(thd, &in_subs->left_expr); + bool failure= in_subs->left_expr->fix_fields_if_needed(thd, + &in_subs->left_expr); thd->lex->current_select= current; thd->where= save_where; if (failure) @@ -1666,8 +1666,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ SELECT_LEX *save_lex= thd->lex->current_select; thd->lex->current_select=subq_lex; - if (!subq_pred->left_expr->fixed && - subq_pred->left_expr->fix_fields(thd, &subq_pred->left_expr)) + if (subq_pred->left_expr->fix_fields_if_needed(thd, &subq_pred->left_expr)) DBUG_RETURN(TRUE); thd->lex->current_select=save_lex; @@ -1777,8 +1776,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) to check for this at name resolution stage, but as a legacy of IN->EXISTS we have in here). */ - if (!sj_nest->sj_on_expr->fixed && - sj_nest->sj_on_expr->fix_fields(thd, &sj_nest->sj_on_expr)) + if (sj_nest->sj_on_expr->fix_fields_if_needed(thd, &sj_nest->sj_on_expr)) { DBUG_RETURN(TRUE); } @@ -1804,9 +1802,8 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) emb_tbl_nest->on_expr= and_items(thd, emb_tbl_nest->on_expr, sj_nest->sj_on_expr); emb_tbl_nest->on_expr->top_level_item(); - if (!emb_tbl_nest->on_expr->fixed && - emb_tbl_nest->on_expr->fix_fields(thd, - &emb_tbl_nest->on_expr)) + if (emb_tbl_nest->on_expr->fix_fields_if_needed(thd, + &emb_tbl_nest->on_expr)) { DBUG_RETURN(TRUE); } @@ -1822,9 +1819,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred) */ save_lex= thd->lex->current_select; thd->lex->current_select=parent_join->select_lex; - if (!parent_join->conds->fixed && - parent_join->conds->fix_fields(thd, - &parent_join->conds)) + if (parent_join->conds->fix_fields_if_needed(thd, &parent_join->conds)) { DBUG_RETURN(1); } @@ -3724,7 +3719,7 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab) re-executing it will not be prepared. To use the Items from its select list we have to prepare (fix_fields) them */ - if (!item->fixed && item->fix_fields(thd, it.ref())) + if (item->fix_fields_if_needed(thd, it.ref())) DBUG_RETURN(TRUE); item= *(it.ref()); // it can be changed by fix_fields DBUG_ASSERT(!item->name.length || item->name.length == strlen(item->name.str)); @@ -5572,8 +5567,7 @@ bool setup_jtbm_semi_joins(JOIN *join, List *join_list, Item *sj_conds= hash_sj_engine->semi_join_conds; (*join_where)= and_items(thd, *join_where, sj_conds); - if (!(*join_where)->fixed) - (*join_where)->fix_fields(thd, join_where); + (*join_where)->fix_fields_if_needed(thd, join_where); } table->table->maybe_null= MY_TEST(join->mixed_implicit_grouping); } diff --git a/sql/set_var.cc b/sql/set_var.cc index 7bf6b9f928d..c9dfeb3e211 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -768,8 +768,7 @@ int set_var::check(THD *thd) if (!value) return 0; - if ((!value->fixed && - value->fix_fields(thd, &value)) || value->check_cols(1)) + if (value->fix_fields_if_needed_for_scalar(thd, &value)) return -1; if (var->check_update_type(value)) { @@ -803,8 +802,7 @@ int set_var::light_check(THD *thd) if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)) return 1; - if (value && ((!value->fixed && value->fix_fields(thd, &value)) || - value->check_cols(1))) + if (value && value->fix_fields_if_needed_for_scalar(thd, &value)) return -1; return 0; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 3ec234759e3..3a9e83d9d09 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -99,7 +99,7 @@ sp_map_item_type(const Type_handler *handler) bool Item_splocal::append_for_log(THD *thd, String *str) { - if (fix_fields(thd, NULL)) + if (fix_fields_if_needed(thd, NULL)) return true; if (limit_clause_param) @@ -137,7 +137,7 @@ bool Item_splocal::append_value_for_log(THD *thd, String *str) bool Item_splocal_row_field::append_for_log(THD *thd, String *str) { - if (fix_fields(thd, NULL)) + if (fix_fields_if_needed(thd, NULL)) return true; if (limit_clause_param) @@ -373,16 +373,14 @@ Item *THD::sp_prepare_func_item(Item **it_addr, uint cols) Item *THD::sp_fix_func_item(Item **it_addr) { DBUG_ENTER("THD::sp_fix_func_item"); - if (!(*it_addr)->fixed && - (*it_addr)->fix_fields(this, it_addr)) + if ((*it_addr)->fix_fields_if_needed(this, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); } it_addr= (*it_addr)->this_item_addr(this, it_addr); - if (!(*it_addr)->fixed && - (*it_addr)->fix_fields(this, it_addr)) + if ((*it_addr)->fix_fields_if_needed(this, it_addr)) { DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 351ddb452d8..6626a054052 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -88,7 +88,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if (param->next) { // first parameter - if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) + if ((*param->item)->fix_fields_if_needed(thd, param->item)) { DBUG_PRINT("info", ("fix_fields() for the first parameter failed")); goto err; @@ -107,7 +107,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, goto err; } // second parameter - if (!(*param->item)->fixed && (*param->item)->fix_fields(thd, param->item)) + if ((*param->item)->fix_fields_if_needed(thd, param->item)) { DBUG_PRINT("info", ("fix_fields() for the second parameter failed")); goto err; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 64427af6319..80939cbe59b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5641,8 +5641,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si calls fix_fields on that item), it's just a check during table reopening for columns that was dropped by the concurrent connection. */ - if (!nj_col->table_field->fixed && - nj_col->table_field->fix_fields(thd, &ref)) + if (nj_col->table_field->fix_fields_if_needed(thd, &ref)) { DBUG_PRINT("info", ("column '%s' was dropped by the concurrent connection", nj_col->table_field->name.str)); @@ -7343,8 +7342,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, if (make_pre_fix) pre_fix->push_back(item, thd->stmt_arena->mem_root); - if ((!item->fixed && item->fix_fields(thd, it.ref())) || - (item= *(it.ref()))->check_cols(1)) + if (item->fix_fields_if_needed_for_scalar(thd, it.ref())) { thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup; thd->lex->allow_sum_func= save_allow_sum_func; @@ -7352,6 +7350,7 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage)); DBUG_RETURN(TRUE); /* purecov: inspected */ } + item= *(it.ref()); // Item might have changed in fix_fields() if (!ref.is_null()) { ref[0]= item; @@ -7982,9 +7981,8 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) { thd->where="on clause"; embedded->on_expr->mark_as_condition_AND_part(embedded); - if ((!embedded->on_expr->fixed && - embedded->on_expr->fix_fields(thd, &embedded->on_expr)) || - embedded->on_expr->check_cols(1)) + if (embedded->on_expr->fix_fields_if_needed_for_bool(thd, + &embedded->on_expr)) return TRUE; } /* @@ -7994,7 +7992,7 @@ bool setup_on_expr(THD *thd, TABLE_LIST *table, bool is_update) if (embedded->sj_subq_pred) { Item **left_expr= &embedded->sj_subq_pred->left_expr; - if (!(*left_expr)->fixed && (*left_expr)->fix_fields(thd, left_expr)) + if ((*left_expr)->fix_fields_if_needed(thd, left_expr)) return TRUE; } @@ -8092,8 +8090,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List &leaves, if ((*conds)->type() == Item::FIELD_ITEM && !derived) wrap_ident(thd, conds); (*conds)->mark_as_condition_AND_part(NO_JOIN_NEST); - if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) || - (*conds)->check_cols(1)) + if ((*conds)->fix_fields_if_needed_for_bool(thd, conds)) goto err_no_arena; } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index b9396c092ef..6a2e956fbf3 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -465,9 +465,7 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived) derived->prep_on_expr= expr->copy_andor_structure(thd); } if (derived->on_expr && - ((!derived->on_expr->fixed && - derived->on_expr->fix_fields(thd, &derived->on_expr)) || - derived->on_expr->check_cols(1))) + derived->on_expr->fix_fields_if_needed_for_bool(thd, &derived->on_expr)) { res= TRUE; /* purecov: inspected */ goto exit_merge; diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc index 6a3cec79160..1b64819732c 100644 --- a/sql/sql_get_diagnostics.cc +++ b/sql/sql_get_diagnostics.cc @@ -217,8 +217,7 @@ Condition_information::aggregate(THD *thd, const Diagnostics_area *da) DBUG_ENTER("Condition_information::aggregate"); /* Prepare the expression for evaluation. */ - if (!m_cond_number_expr->fixed && - m_cond_number_expr->fix_fields(thd, &m_cond_number_expr)) + if (m_cond_number_expr->fix_fields_if_needed(thd, &m_cond_number_expr)) DBUG_RETURN(true); cond_number= m_cond_number_expr->val_int(); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index faf9fcbe906..c2f161d507d 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -630,8 +630,7 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, /* This can only be true for temp tables */ if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - if ((!cond->fixed && - cond->fix_fields(thd, &cond)) || cond->check_cols(1)) + if (cond->fix_fields_if_needed_for_bool(thd, &cond)) return 1; } @@ -695,10 +694,9 @@ mysql_ha_fix_cond_and_key(SQL_HANDLER *handler, { my_bitmap_map *old_map; /* note that 'item' can be changed by fix_fields() call */ - if ((!item->fixed && - item->fix_fields(thd, it_ke.ref())) || - (item= *it_ke.ref())->check_cols(1)) + if (item->fix_fields_if_needed_for_scalar(thd, it_ke.ref())) return 1; + item= *it_ke.ref(); if (item->used_tables() & ~(RAND_TABLE_BIT | PARAM_TABLE_BIT)) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ"); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 085e54dbc90..aa9f3fedd6d 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -611,8 +611,7 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE *table, int *error) { - if (!cond->fixed) - cond->fix_fields(thd, &cond); // can never fail + cond->fix_fields_if_needed(thd, &cond); // can never fail /* Assume that no indexes cover all required fields */ table->covering_keys.clear_all(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 4187cb19c59..a60a6f2975e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1317,7 +1317,7 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) /* check simplicity and prepare unique test of view */ for (trans= trans_start; trans != trans_end; trans++) { - if (!trans->item->fixed && trans->item->fix_fields(thd, &trans->item)) + if (trans->item->fix_fields_if_needed(thd, &trans->item)) { thd->column_usage= saved_column_usage; DBUG_RETURN(TRUE); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index fc1af9837a9..39cf4cd1e46 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2682,15 +2682,9 @@ ha_rows st_select_lex::get_offset() if (offset_limit) { // see comment for st_select_lex::get_limit() - bool fix_fields_successful= true; - if (!offset_limit->fixed) - { - fix_fields_successful= !offset_limit->fix_fields(master_unit()->thd, - NULL); - - DBUG_ASSERT(fix_fields_successful); - } - val= fix_fields_successful ? offset_limit->val_uint() : HA_POS_ERROR; + bool err= offset_limit->fix_fields_if_needed(master_unit()->thd, NULL); + DBUG_ASSERT(!err); + val= err ? HA_POS_ERROR : offset_limit->val_uint(); } return (ha_rows)val; @@ -2729,15 +2723,9 @@ ha_rows st_select_lex::get_limit() fix_fields() implementation. Also added runtime check against a result of fix_fields() in order to handle error condition in non-debug build. */ - bool fix_fields_successful= true; - if (!select_limit->fixed) - { - fix_fields_successful= !select_limit->fix_fields(master_unit()->thd, - NULL); - - DBUG_ASSERT(fix_fields_successful); - } - val= fix_fields_successful ? select_limit->val_uint() : HA_POS_ERROR; + bool err= select_limit->fix_fields_if_needed(master_unit()->thd, NULL); + DBUG_ASSERT(!err); + val= err ? HA_POS_ERROR : select_limit->val_uint(); } return (ha_rows)val; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e5ca2d42210..70caa3b92b9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3328,7 +3328,7 @@ public: List_iterator_fast param_it(prepared_stmt_params); while (Item *param= param_it++) { - if (param->fix_fields(thd, 0) || param->check_cols(1)) + if (param->fix_fields_if_needed_for_scalar(thd, 0)) return true; } return false; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 46a1ad22002..a1307fb0b09 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3709,8 +3709,7 @@ mysql_execute_command(THD *thd) Item **it= lex->value_list.head_ref(); if (!(*it)->basic_const_item() || - (!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || - (*it)->check_cols(1)) + (*it)->fix_fields_if_needed_for_scalar(lex->thd, it)) { my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), MYF(0)); @@ -3819,8 +3818,7 @@ mysql_execute_command(THD *thd) goto error; /* PURGE MASTER LOGS BEFORE 'data' */ it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || - it->check_cols(1)) + if (it->fix_fields_if_needed_for_scalar(lex->thd, &it)) { my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE"); goto error; @@ -5680,7 +5678,7 @@ end_with_restore_list: if (lex->kill_type == KILL_TYPE_ID || lex->kill_type == KILL_TYPE_QUERY) { Item *it= (Item *)lex->value_list.head(); - if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) + if (it->fix_fields_if_needed_for_scalar(lex->thd, &it)) { my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), MYF(0)); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index c0ff1c54549..ffe632d5409 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -146,7 +146,7 @@ Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs) item= item->safe_charset_converter(thd, cs); context->table_list= NULL; thd->where= "convert character set partition constant"; - if (!item || item->fix_fields(thd, (Item**)NULL)) + if (item->fix_fields_if_needed(thd, (Item**)NULL)) item= NULL; thd->where= save_where; context->table_list= save_list; @@ -859,7 +859,7 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, const nesting_map saved_allow_sum_func= thd->lex->allow_sum_func; thd->lex->allow_sum_func= 0; - if (likely(!(error= func_expr->fix_fields(thd, (Item**)&func_expr)))) + if (likely(!(error= func_expr->fix_fields_if_needed(thd, (Item**)&func_expr)))) func_expr->walk(&Item::post_fix_fields_part_expr_processor, 0, NULL); /* diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d4c96ebc535..fd526f9a660 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1656,8 +1656,7 @@ static bool mysql_test_call_fields(Prepared_statement *stmt, while ((item= it++)) { - if ((!item->fixed && item->fix_fields(thd, it.ref())) || - item->check_cols(1)) + if (item->fix_fields_if_needed_for_scalar(thd, it.ref())) goto err; } DBUG_RETURN(FALSE); @@ -2665,8 +2664,7 @@ end: bool LEX::get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer) { - if (prepared_stmt_code->fix_fields(thd, NULL) || - prepared_stmt_code->check_cols(1)) + if (prepared_stmt_code->fix_fields_if_needed_for_scalar(thd, NULL)) return true; const String *str= prepared_stmt_code->val_str(buffer); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 215803c2637..52041cca0d6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -531,7 +531,7 @@ fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, ref->outer_ref= new_ref; ref->ref= &ref->outer_ref; - if (!ref->fixed && ref->fix_fields(thd, 0)) + if (ref->fix_fields_if_needed(thd, 0)) return TRUE; thd->lex->used_tables|= item->used_tables(); thd->lex->current_select->select_list_tables|= item->used_tables(); @@ -1140,9 +1140,7 @@ JOIN::prepare(TABLE_LIST *tables_init, if (having->type() == Item::REF_ITEM && ((Item_ref *)having)->ref_type() == Item_ref::REF) wrap_ident(thd, &having); - bool having_fix_rc= (!having->fixed && - (having->fix_fields(thd, &having) || - having->check_cols(1))); + bool having_fix_rc= having->fix_fields_if_needed_for_bool(thd, &having); select_lex->having_fix_field= 0; if (unlikely(having_fix_rc || thd->is_error())) @@ -2667,10 +2665,10 @@ bool JOIN::add_having_as_table_cond(JOIN_TAB *tab) sort_table_cond))) DBUG_RETURN(true); } - if (tab->select->cond && !tab->select->cond->fixed) - tab->select->cond->fix_fields(thd, 0); - if (tab->pre_idx_push_select_cond && !tab->pre_idx_push_select_cond->fixed) - tab->pre_idx_push_select_cond->fix_fields(thd, 0); + if (tab->select->cond) + tab->select->cond->fix_fields_if_needed(thd, 0); + if (tab->pre_idx_push_select_cond) + tab->pre_idx_push_select_cond->fix_fields_if_needed(thd, 0); tab->select->pre_idx_push_select_cond= tab->pre_idx_push_select_cond; tab->set_select_cond(tab->select->cond, __LINE__); tab->select_cond->top_level_item(); @@ -9340,7 +9338,7 @@ bool JOIN::inject_cond_into_where(Item *injected_cond) } where_item= and_items(thd, conds, where_item); - if (!where_item->fixed && where_item->fix_fields(thd, 0)) + if (where_item->fix_fields_if_needed(thd, 0)) return true; thd->change_item_tree(&select_lex->where, where_item); select_lex->where->top_level_item(); @@ -22896,8 +22894,8 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, original field name, we should additionally check if we have conflict for this name (in case if we would perform lookup in all tables). */ - if (resolution == RESOLVED_BEHIND_ALIAS && !order_item->fixed && - order_item->fix_fields(thd, order->item)) + if (resolution == RESOLVED_BEHIND_ALIAS && + order_item->fix_fields_if_needed_for_order_by(thd, order->item)) return TRUE; /* Lookup the current GROUP field in the FROM clause. */ @@ -22978,11 +22976,10 @@ find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, We check order_item->fixed because Item_func_group_concat can put arguments for which fix_fields already was called. */ - if (!order_item->fixed && - (order_item->fix_fields(thd, order->item) || - (order_item= *order->item)->check_cols(1) || - thd->is_error())) + if (order_item->fix_fields_if_needed_for_order_by(thd, order->item) || + thd->is_error()) return TRUE; /* Wrong field. */ + order_item= *order->item; // Item can change during fix_fields() if (!add_to_all_fields) return FALSE; @@ -24280,7 +24277,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) { Item *new_cond= and_conds(thd, cond_copy, join_tab->select->pre_idx_push_select_cond); - if (!new_cond->fixed && new_cond->fix_fields(thd, &new_cond)) + if (new_cond->fix_fields_if_needed(thd, &new_cond)) error= 1; join_tab->pre_idx_push_select_cond= join_tab->select->pre_idx_push_select_cond= new_cond; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f8702657be7..224e6f0e411 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -8455,8 +8455,7 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) Field_translator *end= table_list->field_translation_end; for (transl= table_list->field_translation; transl < end; transl++) { - if (!transl->item->fixed && - transl->item->fix_fields(thd, &transl->item)) + if (transl->item->fix_fields_if_needed(thd, &transl->item)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -8473,10 +8472,8 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list) { transl->item= item; transl->name= item->name; - if (!item->fixed && item->fix_fields(thd, &transl->item)) - { + if (item->fix_fields_if_needed(thd, &transl->item)) DBUG_RETURN(1); - } } table_list->field_translation= org_transl; table_list->field_translation_end= transl; diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index 7a28ba65ba2..a92d40f6bb3 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -218,16 +218,9 @@ int Sql_cmd_common_signal::eval_signal_informations(THD *thd, Sql_condition *con i <= LAST_DIAG_SET_PROPERTY; i++) { - set= m_set_signal_information.m_item[i]; - if (set) - { - if (! set->fixed) - { - if (set->fix_fields(thd, & set)) - goto end; - m_set_signal_information.m_item[i]= set; - } - } + if ((set= m_set_signal_information.m_item[i]) && + set->fix_fields_if_needed(thd, &m_set_signal_information.m_item[i])) + goto end; } /* diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 6961f821a0a..df3a2dc9c04 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -797,8 +797,7 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, */ trg_field->setup_field(thd, table, NULL); - if (!trg_field->fixed && - trg_field->fix_fields(thd, (Item **)0)) + if (trg_field->fix_fields_if_needed(thd, (Item **)0)) DBUG_RETURN(true); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 6679334552b..783c655d007 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1938,7 +1938,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view) DBUG_PRINT("info", ("thd->column_usage: %d", thd->column_usage)); for (Field_translator *fld= trans; fld < end_of_trans; fld++) { - if (!fld->item->fixed && fld->item->fix_fields(thd, &fld->item)) + if (fld->item->fix_fields_if_needed(thd, &fld->item)) { thd->column_usage= saved_column_usage; DBUG_RETURN(TRUE); diff --git a/sql/table.cc b/sql/table.cc index 4bfe726980e..58e0c0a9189 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -4886,10 +4886,8 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, { if (where->fixed) where->update_used_tables(); - if (!where->fixed && where->fix_fields(thd, &where)) - { + else if (where->fix_fields(thd, &where)) DBUG_RETURN(TRUE); - } /* check that it is not VIEW in which we insert with INSERT SELECT @@ -4919,12 +4917,12 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, } if (tbl == 0) { - if (*conds && !(*conds)->fixed) - res= (*conds)->fix_fields(thd, conds); + if (*conds) + res= (*conds)->fix_fields_if_needed_for_bool(thd, conds); if (!res) *conds= and_conds(thd, *conds, where->copy_andor_structure(thd)); - if (*conds && !(*conds)->fixed && !res) - res= (*conds)->fix_fields(thd, conds); + if (*conds && !res) + res= (*conds)->fix_fields_if_needed_for_bool(thd, conds); } if (arena) thd->restore_active_arena(arena, &backup); @@ -5071,12 +5069,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) { const char *save_where= thd->where; thd->where= "check option"; - if ((!check_option->fixed && - check_option->fix_fields(thd, &check_option)) || - check_option->check_cols(1)) - { + if (check_option->fix_fields_if_needed_for_bool(thd, &check_option)) DBUG_RETURN(TRUE); - } thd->where= save_where; } DBUG_RETURN(FALSE); @@ -8933,7 +8927,7 @@ bool Vers_history_point::resolve_unit(THD *thd) { if (!item) return false; - if (!item->fixed && item->fix_fields(thd, &item)) + if (item->fix_fields_if_needed(thd, &item)) return true; return item->this_item()->type_handler_for_system_time()-> Vers_history_point_resolve_unit(thd, this); diff --git a/sql/unireg.cc b/sql/unireg.cc index a9b47c72a4f..6540e11578b 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -1082,9 +1082,8 @@ static bool make_empty_rec(THD *thd, uchar *buff, uint table_options, field->real_field_type() == MYSQL_TYPE_GEOMETRY)) { Item *expr= field->default_value->expr; - - int res= !expr->fixed && // may be already fixed if ALTER TABLE - expr->fix_fields(thd, &expr); + // may be already fixed if ALTER TABLE + int res= expr->fix_fields_if_needed(thd, &expr); if (!res) res= expr->save_in_field(regfield, 1); if (!res && (field->flags & BLOB_FLAG))