From 259e5243faa88370bbb890342326a324fb648f7d Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Thu, 25 Feb 2021 14:20:11 +0700 Subject: [PATCH 01/19] MDEV-24860: Incorrect behaviour of SET STATEMENT in case it is executed as a prepared statement Running statements with SET STATEMENT FOR clause is handled incorrectly in case the whole statement is executed in prepared statement mode. For example, running of the following statement SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1; results in different definition of the table t1 depending on whether the statement is executed as a prepared or as a regular statement. In first case the column c1 is defined as `c1` varchar(3) DEFAULT NULL in the last case the column c1 is defined as `c1` varchar(3) NOT NULL Different definition for the column c1 arise due to the fact that a value of the data memeber Item_func_concat::maybe_null depends on whether strict mode is on or off. Below is definition of the method fix_fields() of the class Item_str_func that is base class for the class Item_func_concat that is created on parsing the SET STATEMENT FOR clause. bool Item_str_func::fix_fields(THD *thd, Item **ref) { bool res= Item_func::fix_fields(thd, ref); /* In Item_str_func::check_well_formed_result() we may set null_value flag on the same condition as in test() below. */ maybe_null= maybe_null || thd->is_strict_mode(); return res; } Although the clause SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR is parsed on PREPARE phase during processing of the prepared statement, real setting of the sql_mode system variable is done on EXECUTION phase. On the other hand, the method Item_str_func::fix_fields is called on PREPARE phase. In result, thd->is_strict_mode() returns true during calling the method Item_str_func::fix_fields(), the data member maybe_null is assigned the value true and column c1 is defined as DEFAULT NULL. To fix the issue the system variables listed in the SET STATEMENT FOR clause are set at the beginning of handling the PREPARE phase just right before calling the function check_prepared_statement() and their original values restored immediate after return from this function. Additionally, to avoid code duplication the source code used in the function mysql_execute_command for setting variables, specified by SET STATEMENT clause, were extracted to the standalone functions run_set_statement_if_requested(). This new function is called from the function mysql_execute_command() and the method Prepared_statement::prepare(). --- mysql-test/r/set_statement.result | 25 +++ mysql-test/t/set_statement.test | 23 +++ sql/sql_parse.cc | 267 ++++++++++++++++-------------- sql/sql_parse.h | 1 + sql/sql_prepare.cc | 16 ++ 5 files changed, 212 insertions(+), 120 deletions(-) diff --git a/mysql-test/r/set_statement.result b/mysql-test/r/set_statement.result index 845c0f21e3e..cd4859c32e8 100644 --- a/mysql-test/r/set_statement.result +++ b/mysql-test/r/set_statement.result @@ -1217,3 +1217,28 @@ set @rnd=1; select @rnd; @rnd 0 +# +# MDEV-24860: Incorrect behaviour of SET STATEMENT in case +# it is executed as a prepared statement +# +PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1"; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +# Show definition of the table t1 created using Prepared Statement +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(3) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; +# Create the table t1 with the same definition as it used before +# using regular statement execution mode. +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1; +# Show that the table has the same definition as it is in case the table +# created in prepared statement mode. +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` varchar(3) NOT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/t/set_statement.test b/mysql-test/t/set_statement.test index 1c70ed6281a..a5f5c03098d 100644 --- a/mysql-test/t/set_statement.test +++ b/mysql-test/t/set_statement.test @@ -1136,3 +1136,26 @@ while ($1) --enable_query_log --echo # @rnd should be 0 select @rnd; + +--echo # +--echo # MDEV-24860: Incorrect behaviour of SET STATEMENT in case +--echo # it is executed as a prepared statement +--echo # +PREPARE stmt FROM "SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1"; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +--echo # Show definition of the table t1 created using Prepared Statement +SHOW CREATE TABLE t1; + +DROP TABLE t1; + +--echo # Create the table t1 with the same definition as it used before +--echo # using regular statement execution mode. +SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1; + +--echo # Show that the table has the same definition as it is in case the table +--echo # created in prepared statement mode. +SHOW CREATE TABLE t1; + +DROP TABLE t1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 131ba4a86c5..7f756245c83 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2994,6 +2994,146 @@ static bool do_execute_sp(THD *thd, sp_head *sp) } +/** + Check whether the SQL statement being processed is prepended by + SET STATEMENT clause and handle variables assignment if it is. + + @param thd thread handle + @param lex current lex + + @return false in case of success, true in case of error. +*/ + +bool run_set_statement_if_requested(THD *thd, LEX *lex) +{ + if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) + { + Query_arena backup; + DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); + + lex->old_var_list.empty(); + List_iterator_fast it(lex->stmt_var_list); + set_var_base *var; + + if (lex->set_arena_for_set_stmt(&backup)) + return true; + + MEM_ROOT *mem_root= thd->mem_root; + while ((var= it++)) + { + DBUG_ASSERT(var->is_system()); + set_var *o= NULL, *v= (set_var*)var; + if (!v->var->is_set_stmt_ok()) + { + my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); + lex->reset_arena_for_set_stmt(&backup); + lex->old_var_list.empty(); + lex->free_arena_for_set_stmt(); + return true; + } + if (v->var->session_is_default(thd)) + o= new set_var(thd,v->type, v->var, &v->base, NULL); + else + { + switch (v->var->option.var_type & GET_TYPE_MASK) + { + case GET_BOOL: + case GET_INT: + case GET_LONG: + case GET_LL: + { + bool null_value; + longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_int(thd, val))); + } + break; + case GET_UINT: + case GET_ULONG: + case GET_ULL: + { + bool null_value; + ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_uint(thd, val))); + } + break; + case GET_DOUBLE: + { + bool null_value; + double val= v->var->val_real(&null_value, thd, v->type, &v->base); + o= new set_var(thd, v->type, v->var, &v->base, + (null_value ? + (Item *) new (mem_root) Item_null(thd) : + (Item *) new (mem_root) Item_float(thd, val, 1))); + } + break; + default: + case GET_NO_ARG: + case GET_DISABLED: + DBUG_ASSERT(0); + /* fall through */ + case 0: + case GET_FLAGSET: + case GET_ENUM: + case GET_SET: + case GET_STR: + case GET_STR_ALLOC: + { + char buff[STRING_BUFFER_USUAL_SIZE]; + String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; + val= v->var->val_str(&tmp, thd, v->type, &v->base); + if (val) + { + Item_string *str= + new (mem_root) Item_string(thd, v->var->charset(thd), + val->ptr(), val->length()); + o= new set_var(thd, v->type, v->var, &v->base, str); + } + else + o= new set_var(thd, v->type, v->var, &v->base, + new (mem_root) Item_null(thd)); + } + break; + } + } + DBUG_ASSERT(o); + lex->old_var_list.push_back(o, thd->mem_root); + } + lex->reset_arena_for_set_stmt(&backup); + + if (lex->old_var_list.is_empty()) + lex->free_arena_for_set_stmt(); + + if (thd->is_error() || + sql_set_variables(thd, &lex->stmt_var_list, false)) + { + if (!thd->is_error()) + my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); + lex->restore_set_statement_var(); + return true; + } + /* + The value of last_insert_id is remembered in THD to be written to binlog + when it's used *the first time* in the statement. But SET STATEMENT + must read the old value of last_insert_id to be able to restore it at + the end. This should not count at "reading of last_insert_id" and + should not remember last_insert_id for binlog. That is, it should clear + stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. + */ + if (!thd->in_sub_stmt) + { + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; + } + } + return false; +} + + /** Execute command saved in thd and lex->sql_command. @@ -3253,126 +3393,13 @@ mysql_execute_command(THD *thd) thd->get_binlog_format(&orig_binlog_format, &orig_current_stmt_binlog_format); - if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) - { - Query_arena backup; - DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements)); - - lex->old_var_list.empty(); - List_iterator_fast it(lex->stmt_var_list); - set_var_base *var; - - if (lex->set_arena_for_set_stmt(&backup)) - goto error; - - MEM_ROOT *mem_root= thd->mem_root; - while ((var= it++)) - { - DBUG_ASSERT(var->is_system()); - set_var *o= NULL, *v= (set_var*)var; - if (!v->var->is_set_stmt_ok()) - { - my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); - lex->reset_arena_for_set_stmt(&backup); - lex->old_var_list.empty(); - lex->free_arena_for_set_stmt(); - goto error; - } - if (v->var->session_is_default(thd)) - o= new set_var(thd,v->type, v->var, &v->base, NULL); - else - { - switch (v->var->option.var_type & GET_TYPE_MASK) - { - case GET_BOOL: - case GET_INT: - case GET_LONG: - case GET_LL: - { - bool null_value; - longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_int(thd, val))); - } - break; - case GET_UINT: - case GET_ULONG: - case GET_ULL: - { - bool null_value; - ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_uint(thd, val))); - } - break; - case GET_DOUBLE: - { - bool null_value; - double val= v->var->val_real(&null_value, thd, v->type, &v->base); - o= new set_var(thd, v->type, v->var, &v->base, - (null_value ? - (Item *) new (mem_root) Item_null(thd) : - (Item *) new (mem_root) Item_float(thd, val, 1))); - } - break; - default: - case GET_NO_ARG: - case GET_DISABLED: - DBUG_ASSERT(0); - case 0: - case GET_FLAGSET: - case GET_ENUM: - case GET_SET: - case GET_STR: - case GET_STR_ALLOC: - { - char buff[STRING_BUFFER_USUAL_SIZE]; - String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; - val= v->var->val_str(&tmp, thd, v->type, &v->base); - if (val) - { - Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd), - val->ptr(), val->length()); - o= new set_var(thd, v->type, v->var, &v->base, str); - } - else - o= new set_var(thd, v->type, v->var, &v->base, - new (mem_root) Item_null(thd)); - } - break; - } - } - DBUG_ASSERT(o); - lex->old_var_list.push_back(o, thd->mem_root); - } - lex->reset_arena_for_set_stmt(&backup); - if (lex->old_var_list.is_empty()) - lex->free_arena_for_set_stmt(); - if (thd->is_error() || - (res= sql_set_variables(thd, &lex->stmt_var_list, false))) - { - if (!thd->is_error()) - my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET"); - lex->restore_set_statement_var(); - goto error; - } - /* - The value of last_insert_id is remembered in THD to be written to binlog - when it's used *the first time* in the statement. But SET STATEMENT - must read the old value of last_insert_id to be able to restore it at - the end. This should not count at "reading of last_insert_id" and - should not remember last_insert_id for binlog. That is, it should clear - stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. - */ - if (!thd->in_sub_stmt) - { - thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; - } - } + /* + Assign system variables with values specified by the clause + SET STATEMENT var1=value1 [, var2=value2, ...] FOR + if they are any. + */ + if (run_set_statement_if_requested(thd, lex)) + goto error; if (thd->lex->mi.connection_name.str == NULL) thd->lex->mi.connection_name= thd->variables.default_master_connection; diff --git a/sql/sql_parse.h b/sql/sql_parse.h index ce5953696a2..968fa223e1e 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -101,6 +101,7 @@ void mysql_init_multi_delete(LEX *lex); bool multi_delete_set_locks_and_link_aux_tables(LEX *lex); void create_table_set_open_action_and_adjust_tables(LEX *lex); pthread_handler_t handle_bootstrap(void *arg); +bool run_set_statement_if_requested(THD *thd, LEX *lex); int mysql_execute_command(THD *thd); bool do_command(THD *thd); void do_handle_bootstrap(THD *thd); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 3dff2cb8106..fa335465f02 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -4249,6 +4249,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) */ MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); + /* + Set variables specified by + SET STATEMENT var1=value1 [, var2=value2, ...] FOR + clause for duration of prepare phase. Original values of variable + listed in the SET STATEMENT clause is restored right after return + from the function check_prepared_statement() + */ + if (likely(error == 0)) + error= run_set_statement_if_requested(thd, lex); + /* The only case where we should have items in the thd->free_list is after stmt->set_params_from_vars(), which may in some cases create @@ -4267,6 +4277,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; } + /* + Restore original values of variables modified on handling + SET STATEMENT clause. + */ + thd->lex->restore_set_statement_var(); + /* The order is important */ lex->unit.cleanup(); From 1d80e8e4f31b2e361241973467070975f6d80136 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 25 Feb 2021 11:55:08 +0200 Subject: [PATCH 02/19] MENT-1098 Crash during update on 10.4.17 after upgrade from 10.4.10 The reason for the crash was that there was not a write lock to protect against file rotations in the server_audit plugin after an audit plugin patch to changed audit mutexes to read & write locks. The fixes are: * Moving server_audit.c to use read & write locks (which improves performance). * Added functionality in file_logger.c to not do file rotations until it is allowed by the caller (done without any interface changes for the logging service). * Move checking of file size limit to server_audit.c and if it is time to do a rotation change the read lock to a write lock and tell file_logger that it is now allowed to rotate the log files. --- mysys/file_logger.c | 55 +++++++++------ plugin/server_audit/server_audit.c | 104 +++++++++++++++++------------ 2 files changed, 97 insertions(+), 62 deletions(-) diff --git a/mysys/file_logger.c b/mysys/file_logger.c index 71394be7afc..476ed44089e 100644 --- a/mysys/file_logger.c +++ b/mysys/file_logger.c @@ -150,23 +150,34 @@ exit: } +/* + Return 1 if we should rotate the log +*/ + +my_bool logger_time_to_rotate(LOGGER_HANDLE *log) +{ + my_off_t filesize; + if (log->rotations > 0 && + (filesize= my_tell(log->file, MYF(0))) != (my_off_t) -1 && + ((ulonglong) filesize >= log->size_limit)) + return 1; + return 0; +} + + int logger_vprintf(LOGGER_HANDLE *log, const char* fmt, va_list ap) { int result; - my_off_t filesize; char cvtbuf[1024]; size_t n_bytes; flogger_mutex_lock(&log->lock); - if (log->rotations > 0) - if ((filesize= my_tell(log->file, MYF(0))) == (my_off_t) -1 || - ((unsigned long long)filesize >= log->size_limit && - do_rotate(log))) - { - result= -1; - errno= my_errno; - goto exit; /* Log rotation needed but failed */ - } + if (logger_time_to_rotate(log) && do_rotate(log)) + { + result= -1; + errno= my_errno; + goto exit; /* Log rotation needed but failed */ + } n_bytes= my_vsnprintf(cvtbuf, sizeof(cvtbuf), fmt, ap); if (n_bytes >= sizeof(cvtbuf)) @@ -180,21 +191,18 @@ exit: } -int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size) +static int logger_write_r(LOGGER_HANDLE *log, my_bool allow_rotations, + const char *buffer, size_t size) { int result; - my_off_t filesize; flogger_mutex_lock(&log->lock); - if (log->rotations > 0) - if ((filesize= my_tell(log->file, MYF(0))) == (my_off_t) -1 || - ((unsigned long long)filesize >= log->size_limit && - do_rotate(log))) - { - result= -1; - errno= my_errno; - goto exit; /* Log rotation needed but failed */ - } + if (allow_rotations && logger_time_to_rotate(log) && do_rotate(log)) + { + result= -1; + errno= my_errno; + goto exit; /* Log rotation needed but failed */ + } result= (int)my_write(log->file, (uchar *) buffer, size, MYF(0)); @@ -204,6 +212,11 @@ exit: } +int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size) +{ + return logger_write_r(log, TRUE, buffer, size); +} + int logger_rotate(LOGGER_HANDLE *log) { int result; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index cb6b0586524..f6661772df1 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -15,7 +15,7 @@ #define PLUGIN_VERSION 0x104 -#define PLUGIN_STR_VERSION "1.4.10" +#define PLUGIN_STR_VERSION "1.4.11" #define _my_thread_var loc_thread_var @@ -139,6 +139,7 @@ static int loc_file_errno; #define logger_write loc_logger_write #define logger_rotate loc_logger_rotate #define logger_init_mutexts loc_logger_init_mutexts +#define logger_time_to_rotate loc_logger_time_to_rotate static size_t loc_write(File Filedes, const uchar *Buffer, size_t Count) @@ -553,22 +554,22 @@ static struct st_mysql_show_var audit_status[]= {0,0,0} }; -#if defined(HAVE_PSI_INTERFACE) && !defined(FLOGGER_NO_PSI) -/* These belong to the service initialization */ +#ifdef HAVE_PSI_INTERFACE static PSI_mutex_key key_LOCK_operations; -static PSI_mutex_key key_LOCK_atomic; -static PSI_mutex_key key_LOCK_bigbuffer; static PSI_mutex_info mutex_key_list[]= { { &key_LOCK_operations, "SERVER_AUDIT_plugin::lock_operations", - PSI_FLAG_GLOBAL}, + PSI_FLAG_GLOBAL} +#ifndef FLOGGER_NO_PSI + , { &key_LOCK_atomic, "SERVER_AUDIT_plugin::lock_atomic", PSI_FLAG_GLOBAL}, { &key_LOCK_bigbuffer, "SERVER_AUDIT_plugin::lock_bigbuffer", PSI_FLAG_GLOBAL} +#endif /*FLOGGER_NO_PSI*/ }; -#endif -static mysql_mutex_t lock_operations; +#endif /*HAVE_PSI_INTERFACE*/ +static mysql_prlock_t lock_operations; static mysql_mutex_t lock_atomic; static mysql_mutex_t lock_bigbuffer; @@ -1319,19 +1320,41 @@ static void change_connection(struct connection_info *cn, event->ip, event->ip_length); } +/* + Write to the log + + @param take_lock If set, take a read lock (or write lock on rotate). + If not set, the caller has a already taken a write lock +*/ + static int write_log(const char *message, size_t len, int take_lock) { int result= 0; if (take_lock) - flogger_mutex_lock(&lock_operations); + { + /* Start by taking a read lock */ + mysql_prlock_rdlock(&lock_operations); + } if (output_type == OUTPUT_FILE) { - if (logfile && - (is_active= (logger_write(logfile, message, len) == (int) len))) - goto exit; - ++log_write_failures; - result= 1; + if (logfile) + { + my_bool allow_rotate= !take_lock; /* Allow rotate if caller write lock */ + if (take_lock && logger_time_to_rotate(logfile)) + { + /* We have to rotate the log, change above read lock to write lock */ + mysql_prlock_unlock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); + allow_rotate= 1; + } + if (!(is_active= (logger_write_r(logfile, allow_rotate, message, len) == + (int) len))) + { + ++log_write_failures; + result= 1; + } + } } else if (output_type == OUTPUT_SYSLOG) { @@ -1339,9 +1362,8 @@ static int write_log(const char *message, size_t len, int take_lock) syslog_priority_codes[syslog_priority], "%s %.*s", syslog_info, (int) len, message); } -exit: if (take_lock) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); return result; } @@ -1589,7 +1611,7 @@ static int do_log_user(const char *name, int len, return 0; if (take_lock) - flogger_mutex_lock(&lock_operations); + mysql_prlock_rdlock(&lock_operations); if (incl_user_coll.n_users) { @@ -1605,7 +1627,7 @@ static int do_log_user(const char *name, int len, result= 1; if (take_lock) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); return result; } @@ -2496,11 +2518,11 @@ static int server_audit_init(void *p __attribute__((unused))) servhost_len= (uint)strlen(servhost); logger_init_mutexes(); -#if defined(HAVE_PSI_INTERFACE) && !defined(FLOGGER_NO_PSI) +#ifdef HAVE_PSI_INTERFACE if (PSI_server) PSI_server->register_mutex("server_audit", mutex_key_list, 1); #endif - flogger_mutex_init(key_LOCK_operations, &lock_operations, MY_MUTEX_INIT_FAST); + mysql_prlock_init(key_LOCK_operations, &lock_operations); flogger_mutex_init(key_LOCK_operations, &lock_atomic, MY_MUTEX_INIT_FAST); flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST); @@ -2588,7 +2610,7 @@ static int server_audit_deinit(void *p __attribute__((unused))) closelog(); (void) free(big_buffer); - flogger_mutex_destroy(&lock_operations); + mysql_prlock_destroy(&lock_operations); flogger_mutex_destroy(&lock_atomic); flogger_mutex_destroy(&lock_bigbuffer); @@ -2699,7 +2721,7 @@ static void update_file_path(MYSQL_THD thd, fprintf(stderr, "Log file name was changed to '%s'.\n", new_name); if (!maria_55_started || !debug_server_started) - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); if (logging) log_current_query(thd); @@ -2731,7 +2753,7 @@ static void update_file_path(MYSQL_THD thd, file_path= path_buffer; exit_func: if (!maria_55_started || !debug_server_started) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); ADD_ATOMIC(internal_stop_logging, -1); } @@ -2747,9 +2769,9 @@ static void update_file_rotations(MYSQL_THD thd __attribute__((unused)), if (!logging || output_type != OUTPUT_FILE) return; - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); logfile->rotations= rotations; - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); } @@ -2765,9 +2787,9 @@ static void update_file_rotate_size(MYSQL_THD thd __attribute__((unused)), if (!logging || output_type != OUTPUT_FILE) return; - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); logfile->size_limit= file_rotate_size; - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); } @@ -2812,7 +2834,7 @@ static void update_incl_users(MYSQL_THD thd, char *new_users= (*(char **) save) ? *(char **) save : empty_str; size_t new_len= strlen(new_users) + 1; if (!maria_55_started || !debug_server_started) - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); mark_always_logged(thd); if (new_len > sizeof(incl_user_buffer)) @@ -2826,7 +2848,7 @@ static void update_incl_users(MYSQL_THD thd, error_header(); fprintf(stderr, "server_audit_incl_users set to '%s'.\n", incl_users); if (!maria_55_started || !debug_server_started) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); } @@ -2837,7 +2859,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)), char *new_users= (*(char **) save) ? *(char **) save : empty_str; size_t new_len= strlen(new_users) + 1; if (!maria_55_started || !debug_server_started) - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); mark_always_logged(thd); if (new_len > sizeof(excl_user_buffer)) @@ -2851,7 +2873,7 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)), error_header(); fprintf(stderr, "server_audit_excl_users set to '%s'.\n", excl_users); if (!maria_55_started || !debug_server_started) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); } @@ -2864,7 +2886,7 @@ static void update_output_type(MYSQL_THD thd, return; ADD_ATOMIC(internal_stop_logging, 1); - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); if (logging) { log_current_query(thd); @@ -2878,7 +2900,7 @@ static void update_output_type(MYSQL_THD thd, if (logging) start_logging(); - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); ADD_ATOMIC(internal_stop_logging, -1); } @@ -2908,9 +2930,9 @@ static void update_syslog_priority(MYSQL_THD thd __attribute__((unused)), if (syslog_priority == new_priority) return; - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); mark_always_logged(thd); - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); error_header(); fprintf(stderr, "SysLog priority was changed from '%s' to '%s'.\n", syslog_priority_names[syslog_priority], @@ -2929,7 +2951,7 @@ static void update_logging(MYSQL_THD thd, ADD_ATOMIC(internal_stop_logging, 1); if (!maria_55_started || !debug_server_started) - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); if ((logging= new_logging)) { start_logging(); @@ -2946,7 +2968,7 @@ static void update_logging(MYSQL_THD thd, } if (!maria_55_started || !debug_server_started) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); ADD_ATOMIC(internal_stop_logging, -1); } @@ -2961,13 +2983,13 @@ static void update_mode(MYSQL_THD thd __attribute__((unused)), ADD_ATOMIC(internal_stop_logging, 1); if (!maria_55_started || !debug_server_started) - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); mark_always_logged(thd); error_header(); fprintf(stderr, "Logging mode was changed from %d to %d.\n", mode, new_mode); mode= new_mode; if (!maria_55_started || !debug_server_started) - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); ADD_ATOMIC(internal_stop_logging, -1); } @@ -2982,14 +3004,14 @@ static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)), syslog_ident= syslog_ident_buffer; error_header(); fprintf(stderr, "SYSYLOG ident was changed to '%s'\n", syslog_ident); - flogger_mutex_lock(&lock_operations); + mysql_prlock_wrlock(&lock_operations); mark_always_logged(thd); if (logging && output_type == OUTPUT_SYSLOG) { stop_logging(); start_logging(); } - flogger_mutex_unlock(&lock_operations); + mysql_prlock_unlock(&lock_operations); } From 25ecf8ed4b4cbca69a9fa09c27bbd4e5c83fafe3 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Fri, 26 Feb 2021 13:26:00 +0400 Subject: [PATCH 03/19] MDEV-24965 With ALTER USER ...IDENTIFIED BY command, password doesn't replaced by asterisks in audit log. Check for the ALTER USER command added. --- mysql-test/suite/plugins/r/server_audit.result | 3 +++ mysql-test/suite/plugins/t/server_audit.test | 1 + plugin/server_audit/server_audit.c | 3 +++ 3 files changed, 7 insertions(+) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 3fce3346f29..ff22cdff8d6 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -118,6 +118,7 @@ CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; SET PASSWORD FOR u1 = PASSWORD('pwd 098'); CREATE USER u3 IDENTIFIED BY ''; +ALTER USER u3 IDENTIFIED BY 'pwd-456'; drop user u1, u2, u3; set global server_audit_events='query_ddl'; create table t1(id int); @@ -382,6 +383,8 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'ALTER USER u3 IDENTIFIED BY \'pwd-456\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index fa5bd7e1349..6c75c3bf732 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -95,6 +95,7 @@ CREATE USER u1 IDENTIFIED BY 'pwd-123'; GRANT ALL ON sa_db TO u2 IDENTIFIED BY "pwd-321"; SET PASSWORD FOR u1 = PASSWORD('pwd 098'); CREATE USER u3 IDENTIFIED BY ''; +ALTER USER u3 IDENTIFIED BY 'pwd-456'; drop user u1, u2, u3; set global server_audit_events='query_ddl'; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index f6661772df1..9a954365d83 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -819,6 +819,7 @@ enum sa_keywords SQLCOM_DML, SQLCOM_GRANT, SQLCOM_CREATE_USER, + SQLCOM_ALTER_USER, SQLCOM_CHANGE_MASTER, SQLCOM_CREATE_SERVER, SQLCOM_SET_OPTION, @@ -926,6 +927,7 @@ struct sa_keyword passwd_keywords[]= { {3, "SET", &password_word, SQLCOM_SET_OPTION}, {5, "ALTER", &server_word, SQLCOM_ALTER_SERVER}, + {5, "ALTER", &user_word, SQLCOM_ALTER_USER}, {5, "GRANT", 0, SQLCOM_GRANT}, {6, "CREATE", &user_word, SQLCOM_CREATE_USER}, {6, "CREATE", &server_word, SQLCOM_CREATE_SERVER}, @@ -1845,6 +1847,7 @@ do_log_query: { case SQLCOM_GRANT: case SQLCOM_CREATE_USER: + case SQLCOM_ALTER_USER: csize+= escape_string_hide_passwords(query, query_len, uh_buffer, uh_buffer_size, "IDENTIFIED", 10, "BY", 2, 0); From dd9e5827a68c7864d61af44a4dea6932f963c55c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 25 Feb 2021 14:10:25 +0100 Subject: [PATCH 04/19] mtr --gdb: fix for --rr and for a warning use _RR_TRACE_DIR=dir instead of -o dir, as the former can store multiple traces in dir (if, e.g., the test restarts mysqld) suppress uninitialized warning when $exe is undefined (--manual-XXX) --- mysql-test/lib/My/Debugger.pm | 3 ++- mysql-test/mysql-test-run.pl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/My/Debugger.pm b/mysql-test/lib/My/Debugger.pm index d2add55d680..a2d5f2a5435 100644 --- a/mysql-test/lib/My/Debugger.pm +++ b/mysql-test/lib/My/Debugger.pm @@ -74,7 +74,8 @@ my %debuggers = ( options => '-f -o {log} {exe} {args}', }, rr => { - options => 'record -o {log} {exe} {args}', + options => '_RR_TRACE_DIR={log} rr record {exe} {args}', + run => 'env', pre => sub { ::mtr_error('rr requires kernel.perf_event_paranoid <= 1') if ::mtr_grab_file('/proc/sys/kernel/perf_event_paranoid') > 1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 07f103ba91e..fd25c28dc06 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -5071,7 +5071,7 @@ sub mysqld_start ($$) { $ENV{'MYSQLD_LAST_CMD'}= "$exe @$args"; My::Debugger::setup_args(\$args, \$exe, $mysqld->name()); - $ENV{'VALGRIND_TEST'}= $opt_valgrind = int($exe && $exe eq 'valgrind'); + $ENV{'VALGRIND_TEST'}= $opt_valgrind = int(($exe || '') eq 'valgrind'); # Remove the old pidfile if any unlink($mysqld->value('pid-file')); From a18b39e3f49f4916792b72abd7f0fc153a7454fa Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 1 Mar 2021 20:08:14 +0400 Subject: [PATCH 05/19] MDEV-24965 With ALTER USER ...IDENTIFIED BY command, password doesn't replaced by asterisks in audit log. Test result fixed. --- mysql-test/suite/plugins/r/server_audit.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index ff22cdff8d6..bbb3a62f9b4 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -383,7 +383,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, -TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'ALTER USER u3 IDENTIFIED BY \'pwd-456\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'ALTER USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, From 43a0a8139727314f89fc0f0f0d2ba80ffa33b221 Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 Feb 2021 19:42:43 +0200 Subject: [PATCH 06/19] Fixed printing of wring filname "maria_open" in maria.maria-recovery2.test eprintf() was missing a va_start(), which caused wrong filename to be printed when printing recovery trace. Added also missing new line when printing "Table is crashed" to trace file --- storage/maria/ma_recovery.c | 1 + storage/maria/ma_recovery_util.c | 1 + 2 files changed, 2 insertions(+) diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 5c3dae2708d..6cc5b423720 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -1447,6 +1447,7 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id) } if (maria_is_crashed(info)) { + tprint(tracef, "\n"); eprint(tracef, "Table '%s' is crashed, skipping it. Please repair it with" " aria_chk -r", share->open_file_name.str); recovery_found_crashed_tables++; diff --git a/storage/maria/ma_recovery_util.c b/storage/maria/ma_recovery_util.c index 3bbda614991..fe43d812600 100644 --- a/storage/maria/ma_recovery_util.c +++ b/storage/maria/ma_recovery_util.c @@ -98,6 +98,7 @@ void eprint(FILE *trace_file __attribute__ ((unused)), fputc('\n', trace_file); if (trace_file != stderr) { + va_start(args, format); my_printv_error(HA_ERR_INITIALIZATION, format, MYF(0), args); } va_end(args); From 6983ce704baff7a6e5dd411a289e3580bc7bea1a Mon Sep 17 00:00:00 2001 From: Monty Date: Sat, 27 Feb 2021 19:56:46 +0200 Subject: [PATCH 07/19] MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE... The failure happened for group by queries when all tables where marked as 'const tables' (tables with 0-1 matching rows) and no row matched the where clause and there was in addition a direct reference to a field. In this case the field would not be properly reset and the query would return 'random data' that happended to be in table->record[0]. Fixed by marking all const tables as null tables in this particular case. Sergei also provided an extra test case for the code. @reviewer Sergei Petrunia --- mysql-test/main/group_by.result | 29 +++++++++++ mysql-test/main/group_by.test | 23 +++++++++ sql/sql_select.cc | 87 +++++++++++++++++++++++++++++---- sql/table.h | 6 +++ 4 files changed, 135 insertions(+), 10 deletions(-) diff --git a/mysql-test/main/group_by.result b/mysql-test/main/group_by.result index 246cceb96c3..8be5b4d29b9 100644 --- a/mysql-test/main/group_by.result +++ b/mysql-test/main/group_by.result @@ -2934,5 +2934,34 @@ f COUNT(*) NULL 1 DROP TABLE t1; # +# MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE +# +CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT ''); +INSERT INTO t1 (a) VALUES ('foo'); +CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL; +SELECT * from t2; +f1 f2 +NULL NULL +SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL; +f1 f2 +NULL NULL +SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0; +f1 f2 +NULL NULL +drop table t1,t2; +# Extra test by to check the fix for MDEV-24710 +create table t20 (pk int primary key, a int); +insert into t20 values (1,1); +create table t21 (pk int primary key, b int not null); +insert into t21 values (1,1); +create table t22 (a int); +insert into t22 values (1),(2); +select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10 +where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22; +a SUBQ +1 NULL +2 NULL +drop table t20, t21, t22; +# # End of 10.3 tests # diff --git a/mysql-test/main/group_by.test b/mysql-test/main/group_by.test index 2866fab3822..8d690222bcc 100644 --- a/mysql-test/main/group_by.test +++ b/mysql-test/main/group_by.test @@ -2040,6 +2040,29 @@ INSERT INTO t1 VALUES ('2032-10-08'); SELECT d != '2023-03-04' AS f, COUNT(*) FROM t1 GROUP BY d WITH ROLLUP; DROP TABLE t1; +--echo # +--echo # MDEV-24710 Uninitialized value upon CREATE .. SELECT ... VALUE +--echo # + +CREATE TABLE t1 (a VARCHAR(8) NOT NULL DEFAULT ''); +INSERT INTO t1 (a) VALUES ('foo'); +CREATE TABLE t2 AS SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL; +SELECT * from t2; +SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL; +SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE 1=0; +drop table t1,t2; + +--echo # Extra test by to check the fix for MDEV-24710 + +create table t20 (pk int primary key, a int); +insert into t20 values (1,1);create table t21 (pk int primary key, b int not null); +insert into t21 values (1,1); +create table t22 (a int); +insert into t22 values (1),(2); +select a, (select max(t21.b) from t20 left join t21 on t21.pk=t20.a+10 + where t20.pk=1 and rand(123) < 0.5) as SUBQ from t22; +drop table t20, t21, t22; + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c802aa9c18e..7658d843d8b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13668,22 +13668,71 @@ return_zero_rows(JOIN *join, select_result *result, List &tables, DBUG_RETURN(0); } -/* - used only in JOIN::clear +/** + used only in JOIN::clear (always) and in do_select() + (if there where no matching rows) + + @param join JOIN + @param cleared_tables If not null, clear also const tables and mark all + cleared tables in the map. cleared_tables is only + set when called from do_select() when there is a + group function and there where no matching rows. */ -static void clear_tables(JOIN *join) + +static void clear_tables(JOIN *join, table_map *cleared_tables) { /* - must clear only the non-const tables, as const tables - are not re-calculated. + must clear only the non-const tables as const tables are not re-calculated. */ for (uint i= 0 ; i < join->table_count ; i++) { - if (!(join->table[i]->map & join->const_table_map)) - mark_as_null_row(join->table[i]); // All fields are NULL + TABLE *table= join->table[i]; + + if (table->null_row) + continue; // Nothing more to do + if (!(table->map & join->const_table_map) || cleared_tables) + { + if (cleared_tables) + { + (*cleared_tables)|= (((table_map) 1) << i); + if (table->s->null_bytes) + { + /* + Remember null bits for the record so that we can restore the + original const record in unclear_tables() + */ + memcpy(table->record[1], table->null_flags, table->s->null_bytes); + } + } + mark_as_null_row(table); // All fields are NULL + } } } + +/** + Reverse null marking for tables and restore null bits. + + We have to do this because the tables may be re-used in a sub query + and the subquery will assume that the const tables contains the original + data before clear_tables(). +*/ + +static void unclear_tables(JOIN *join, table_map *cleared_tables) +{ + for (uint i= 0 ; i < join->table_count ; i++) + { + if ((*cleared_tables) & (((table_map) 1) << i)) + { + TABLE *table= join->table[i]; + if (table->s->null_bytes) + memcpy(table->null_flags, table->record[1], table->s->null_bytes); + unmark_as_null_row(table); + } + } +} + + /***************************************************************************** Make som simple condition optimization: If there is a test 'field = const' change all refs to 'field' to 'const' @@ -19194,6 +19243,7 @@ do_select(JOIN *join, Procedure *procedure) if (join->only_const_tables() && !join->need_tmp) { Next_select_func end_select= setup_end_select_func(join, NULL); + /* HAVING will be checked after processing aggregate functions, But WHERE should checked here (we alredy have read tables). @@ -19220,12 +19270,29 @@ do_select(JOIN *join, Procedure *procedure) } else if (join->send_row_on_empty_set()) { + table_map cleared_tables= (table_map) 0; + if (end_select == end_send_group) + { + /* + Was a grouping query but we did not find any rows. In this case + we clear all tables to get null in any referenced fields, + like in case of: + SELECT MAX(a) AS f1, a AS f2 FROM t1 WHERE VALUE(a) IS NOT NULL + */ + clear_tables(join, &cleared_tables); + } if (!join->having || join->having->val_int()) { List *columns_list= (procedure ? &join->procedure_fields_list : join->fields); rc= join->result->send_data(*columns_list) > 0; } + /* + We have to remove the null markings from the tables as this table + may be part of a sub query that is re-evaluated + */ + if (cleared_tables) + unclear_tables(join, &cleared_tables); } /* An error can happen when evaluating the conds @@ -20197,8 +20264,8 @@ join_read_const_table(THD *thd, JOIN_TAB *tab, POSITION *pos) if ((table->null_row= MY_TEST((*tab->on_expr_ref)->val_int() == 0))) mark_as_null_row(table); } - if (!table->null_row) - table->maybe_null=0; + if (!table->null_row && ! tab->join->mixed_implicit_grouping) + table->maybe_null= 0; { JOIN *join= tab->join; @@ -25331,7 +25398,7 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg, TABL void JOIN::clear() { - clear_tables(this); + clear_tables(this, 0); copy_fields(&tmp_table_param); if (sum_funcs) diff --git a/sql/table.h b/sql/table.h index 3c31a6364df..6a4c6eb2a03 100644 --- a/sql/table.h +++ b/sql/table.h @@ -3145,6 +3145,12 @@ inline void mark_as_null_row(TABLE *table) bfill(table->null_flags,table->s->null_bytes,255); } +inline void unmark_as_null_row(TABLE *table) +{ + table->null_row=0; + table->status= STATUS_NO_RECORD; +} + bool is_simple_order(ORDER *order); class Open_tables_backup; From 415409579af68ee2e3c55d5294d7bb5e6397b03f Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 1 Mar 2021 14:44:18 +0200 Subject: [PATCH 08/19] MDEV-24958 Server crashes in my_strtod ... with DEFAULT(blob) Fixes also: MDEV-24942 Server crashes in _ma_rec_pack... with DEFAULT() on BLOB This was caused by two different bugs, both related to that the default value for the blob was not calculated before it was used: - There where now Item_default_value::..result() wrappers, which is needed as item in HAVING uses these. This causes crashes when using a reference to a DEFAULT(blob_field) in HAVING. It also caused wrong results when used with other fields with default value expressions that are not constants. - create_tmp_field() did not take into account that blob fields with default expressions are not yet initialized. Fixed by treating Item_default_value(blob) like a normal item expression. --- mysql-test/main/having.result | 33 ++++++++++++++++++++++++ mysql-test/main/having.test | 20 +++++++++++++++ sql/item.cc | 47 ++++++++++++++++++++++++++++++++--- sql/item.h | 10 ++++++++ sql/sql_select.cc | 24 ++++++++++++++++-- 5 files changed, 129 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result index f37cc48772e..233843de36f 100644 --- a/mysql-test/main/having.result +++ b/mysql-test/main/having.result @@ -846,3 +846,36 @@ t r DROP TABLE t1; DROP FUNCTION next_seq_value; DROP TABLE series; +# +# MDEV-24958 Server crashes in my_strtod / +# Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob) +# +# MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with +# DEFAULT() on BLOB +# +CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A'); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f); +f +foo +bar +SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5; +h +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0; +h +A +A +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A'; +h +A +A +alter table t1 add column b int default (rand()+1+3); +select default(b) AS h FROM t1 HAVING h > "2"; +h +# +# +drop table t1; diff --git a/mysql-test/main/having.test b/mysql-test/main/having.test index 179af14559f..8b0cc244f51 100644 --- a/mysql-test/main/having.test +++ b/mysql-test/main/having.test @@ -890,3 +890,23 @@ SELECT t, next_seq_value() r FROM t1 FORCE INDEX(t) DROP TABLE t1; DROP FUNCTION next_seq_value; DROP TABLE series; + +--echo # +--echo # MDEV-24958 Server crashes in my_strtod / +--echo # Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob) +--echo # +--echo # MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with +--echo # DEFAULT() on BLOB +--echo # + +CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A'); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f); +SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5; +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0; +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A'; + +alter table t1 add column b int default (rand()+1+3); +--replace_column 1 # +select default(b) AS h FROM t1 HAVING h > "2"; +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 522fef57699..7b15c7ddb43 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9341,7 +9341,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) } thd->column_usage= save_column_usage; - real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { @@ -9364,7 +9363,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) def_field->reset_fields(); // If non-constant default value expression or a blob if (def_field->default_value && - (def_field->default_value->flags || def_field->flags & BLOB_FLAG)) + (def_field->default_value->flags || (def_field->flags & BLOB_FLAG))) { uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length()); if (!newptr) @@ -9461,11 +9460,53 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) return Item_field::save_in_field(field_arg, no_conversions); } +double Item_default_value::val_result() +{ + calculate(); + return Item_field::val_result(); +} + +longlong Item_default_value::val_int_result() +{ + calculate(); + return Item_field::val_int_result(); +} + +String *Item_default_value::str_result(String* tmp) +{ + calculate(); + return Item_field::str_result(tmp); +} + +bool Item_default_value::val_bool_result() +{ + calculate(); + return Item_field::val_bool_result(); +} + +bool Item_default_value::is_null_result() +{ + calculate(); + return Item_field::is_null_result(); +} + +my_decimal *Item_default_value::val_decimal_result(my_decimal *decimal_value) +{ + calculate(); + return Item_field::val_decimal_result(decimal_value); +} + +bool Item_default_value::get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate) +{ + calculate(); + return Item_field::get_date_result(ltime, fuzzydate); +} + table_map Item_default_value::used_tables() const { if (!field || !field->default_value) return static_cast(0); - if (!field->default_value->expr) // not fully parsed field + if (!field->default_value->expr) // not fully parsed field return static_cast(RAND_TABLE_BIT); return field->default_value->expr->used_tables(); } diff --git a/sql/item.h b/sql/item.h index 9200dd80ee8..9fa384f0947 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5859,6 +5859,16 @@ public: longlong val_int(); my_decimal *val_decimal(my_decimal *decimal_value); bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate); + + /* Result variants */ + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *val); + bool val_bool_result(); + bool is_null_result(); + bool get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate); + bool send(Protocol *protocol, st_value *buffer); int save_in_field(Field *field_arg, bool no_conversions); bool save_in_param(THD *thd, Item_param *param) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7658d843d8b..ce820946908 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17224,7 +17224,13 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) the record in the original table. If modify_item is 0 then fill_record() will update the temporary table - + @param table_cant_handle_bit_fields + Set to 1 if the temporary table cannot handle bit + fields. Only set for heap tables when the bit field + is part of an index. + @param make_copy_field + Set when using with rollup when we want to have + an exact copy of the field. @retval 0 on error @retval @@ -17261,8 +17267,22 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); return result; } - case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: + { + Field *field= ((Item_default_value*) item)->field; + if (field->default_value && (field->flags & BLOB_FLAG)) + { + /* + We have to use a copy function when using a blob with default value + as the we have to calcuate the default value before we can use it. + */ + return create_tmp_field_from_item(thd, item, table, + (make_copy_field ? 0 : copy_func), + modify_item); + } + } + /* Fall through */ + case Item::FIELD_ITEM: case Item::CONTEXTUALLY_TYPED_VALUE_ITEM: case Item::INSERT_VALUE_ITEM: case Item::TRIGGER_FIELD_ITEM: From 3f15d3bad986c36317be75607c6a928ef4978028 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 1 Mar 2021 17:51:44 +0200 Subject: [PATCH 09/19] Fixed unit test to not 'bail out' if some tests are not compiled. Before the changes two things could happen: - "path required name explain_filename path" error - unit test never finishead (as it tried to execute just /bin/sh as a test case) --- mysql-test/suite/unit/suite.pm | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/unit/suite.pm b/mysql-test/suite/unit/suite.pm index c8180c59240..43c9e115de6 100644 --- a/mysql-test/suite/unit/suite.pm +++ b/mysql-test/suite/unit/suite.pm @@ -20,7 +20,6 @@ sub start_test { ($path, $args) = ($cmd, , [ ]) } - my $oldpwd=getcwd(); chdir $::opt_vardir; my $proc=My::SafeProcess->new @@ -44,15 +43,17 @@ sub start_test { my (@ctest_list)= `cd "$bin" && ctest $ctest_vs --show-only --verbose`; return "No ctest" if $?; + $ENV{MYSQL_TEST_PLUGINDIR}=$::plugindir; + my ($command, %tests, $prefix); for (@ctest_list) { chomp; - if (/^\d+: Test command: +/) { - $command= $'; + if (/^\d+: Test command: +([^ \t]+)/) { + $command= $1; $prefix= /libmariadb/ ? 'conc_' : ''; - } elsif (/^ +Test +#\d+: +/) { - if ($command ne "NOT_AVAILABLE") { - $tests{$prefix.$'}=$command; + } elsif (/^ +Test +#\d+: ([^ \t]+)/) { + if ($command ne "NOT_AVAILABLE" && $command ne "/bin/sh") { + $tests{$prefix.$1}=$command; } } } From c25e6f91da2eb04fe222aac1c79c6a5c1f94c760 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 1 Mar 2021 22:08:47 +0200 Subject: [PATCH 10/19] Fixed typo in comment --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 54e382a6c24..61b6023c6a1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7759,7 +7759,7 @@ static bool mysql_inplace_alter_table(THD *thd, Rename to the new name (if needed) will be handled separately below. TODO: remove this check of thd->is_error() (now it intercept - errors in some val_*() methoids and bring some single place to + errors in some val_*() methods and bring some single place to such error interception). */ if (mysql_rename_table(db_type, &alter_ctx->new_db, &alter_ctx->tmp_name, From 0f81ca6a0bb21fbba4bca93a7555f7c8e6357b47 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 1 Mar 2021 09:40:33 -0800 Subject: [PATCH 11/19] MDEV-24919 Crash with subselect formed by table value constructor and used in set function If a subselect is formed by a table value constructor (TVC) then the following transformation is applied at the prepare stage: VALUES (v1), ... (vn) => SELECT * FROM (VALUES (v1), ... (vn)) tvc_x. The transformation is performed by the function wrap_tvc() that resets THD::LEX::current select to the top level select of the result of the transformation. After the call of wrap_tvc() in the function Item_subselect::wrap_tvc_into_select() the field THD::LEX::current must be reset to the same select as before the call. It was not done. As a result if the subselect formed by a TVC was an argument of a set function then an assertion was hit in the function Item_sum::check_sum_func(). Approved by Oleksandr Byelkin --- mysql-test/main/table_value_constr.result | 6 ++++++ mysql-test/main/table_value_constr.test | 6 ++++++ sql/sql_tvc.cc | 15 +++++---------- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/mysql-test/main/table_value_constr.result b/mysql-test/main/table_value_constr.result index 603f21a772d..d2965ab1f6c 100644 --- a/mysql-test/main/table_value_constr.result +++ b/mysql-test/main/table_value_constr.result @@ -2881,4 +2881,10 @@ NULL deallocate prepare stmt; drop view v1; drop table t1,t2,t3; +# +# MDEV-24919: subselect formed by TVC and used in set function +# +select sum((values(1))); +sum((values(1))) +1 End of 10.3 tests diff --git a/mysql-test/main/table_value_constr.test b/mysql-test/main/table_value_constr.test index 2246a19d306..88d0ac2fbbf 100644 --- a/mysql-test/main/table_value_constr.test +++ b/mysql-test/main/table_value_constr.test @@ -1516,4 +1516,10 @@ deallocate prepare stmt; drop view v1; drop table t1,t2,t3; +--echo # +--echo # MDEV-24919: subselect formed by TVC and used in set function +--echo # + +select sum((values(1))); + --echo End of 10.3 tests diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc index 0a771b592e4..cb056b0e15f 100644 --- a/sql/sql_tvc.cc +++ b/sql/sql_tvc.cc @@ -648,7 +648,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, st_select_lex *parent_select) { LEX *lex= thd->lex; - select_result *save_result= thd->lex->result; + select_result *save_result= lex->result; uint8 save_derived_tables= lex->derived_tables; thd->lex->result= NULL; @@ -729,13 +729,13 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl, if (arena) thd->restore_active_arena(arena, &backup); - thd->lex->result= save_result; + lex->result= save_result; return wrapper_sl; err: if (arena) thd->restore_active_arena(arena, &backup); - thd->lex->result= save_result; + lex->result= save_result; lex->derived_tables= save_derived_tables; return 0; } @@ -819,14 +819,9 @@ Item_subselect::wrap_tvc_into_select(THD *thd, st_select_lex *tvc_sl) { if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE) ((subselect_single_select_engine *) engine)->change_select(wrapper_sl); - lex->current_select= wrapper_sl; - return wrapper_sl; - } - else - { - lex->current_select= parent_select; - return 0; } + lex->current_select= parent_select; + return wrapper_sl; } From fc77431624b8d4dc966cd3855c16bee856b05645 Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Tue, 2 Mar 2021 19:09:44 +0700 Subject: [PATCH 12/19] MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement Attempt to execute EXPLAIN statement on multi-table DELETE statement leads to firing firing of the assertion DBUG_ASSERT(! is_set()); in the method Diagnostics_area::set_eof_status. For example, above mentioned assertion failure happens in case any of the following statements EXPLAIN DELETE FROM t1.* USING t1 EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b are executed in prepared statement mode provided the table t1 does exist. This assertion is hit by the reason that a status of Diagnostics_area is set twice. The first time it is set from the function do_select() when the method multi_delete::send_eof() called. The second time it is set when the method Explain_query::send_explain() calls the method select_send::send_eof (this method invokes the method Diagnostics_area::set_eof_status that finally hits assertion) The second invocation for a setter method of the class Diagnostics_area is correct and run to send a response containing explain data. But first invocation of a setter method of the class Diagnostics_area is wrong since the function do_select() shouldn't be called at all for handling of the EXPLAIN statement. The reason by that the function do_select() is called during handling of the EXPLAIN statement is that the flag SELECT_DESCRIBE not set in the data member JOIN::select_options. The flag SELECT_DESCRIBE if is copied from values select_lex->options. During parsing of EXPLAIN statement this flag is set but latter reset from the function reinit_stmt_before_use() that is called on execution of prepared statement. void reinit_stmt_before_use(THD *thd, LEX *lex) { ... for (; sl; sl= sl->next_select_in_list()) { if (sl->changed_elements & TOUCHED_SEL_COND) { /* remove option which was put by mysql_explain_union() */ sl->options&= ~SELECT_DESCRIBE; ... } ... } So, to fix the issue the flag SELECT_DESCRIBE is set forcibly at the mysql_select() function in case thd->lex->describe set, that is in case EXPLAIN being executed. --- mysql-test/r/ps.result | 17 +++++++++++++++++ mysql-test/t/ps.test | 14 ++++++++++++++ sql/sql_select.cc | 3 +++ 3 files changed, 34 insertions(+) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 076c7d9abda..17284a3cad8 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -5402,5 +5402,22 @@ EXISTS(SELECT 1 FROM t1 GROUP BY a IN (select a from t1)) 0 DROP TABLE t1; # +# MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +# +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE a system NULL NULL NULL NULL 0 const row not found +1 SIMPLE b system NULL NULL NULL NULL 0 const row not found +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found +DEALLOCATE PREPARE stmt; +DROP TABLE t1; +# # End of 10.2 tests # diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 1b1f88094ff..a267c8b0e42 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -4912,6 +4912,20 @@ EXECUTE stmt; EXECUTE stmt; DROP TABLE t1; +--echo # +--echo # MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +--echo # + +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP TABLE t1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aa3474dff5f..f30ce088bc4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3801,6 +3801,9 @@ mysql_select(THD *thd, } else { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + /* When in EXPLAIN, delay deleting the joins so that they are still available when we're producing EXPLAIN EXTENDED warning text. From 82efe4a15a985c3902e80eb7e1a70841c08d9f2e Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 2 Mar 2021 14:13:39 +0200 Subject: [PATCH 13/19] MDEV-23843 Assertions in Diagnostics_area upon table operations under FTWRL Fixed binary logging in ANALYZE TABLE to work as optimize table --- mysql-test/main/flush_and_binlog.result | 11 +++++++++++ mysql-test/main/flush_and_binlog.test | 14 ++++++++++++++ sql/sql_admin.cc | 2 ++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/main/flush_and_binlog.result b/mysql-test/main/flush_and_binlog.result index b9560964046..a1d73c6590f 100644 --- a/mysql-test/main/flush_and_binlog.result +++ b/mysql-test/main/flush_and_binlog.result @@ -20,3 +20,14 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction connection default; disconnect con1; unlock tables; +# Second test from MDEV-23843 +CREATE TABLE t (a INT); +FLUSH TABLES WITH READ LOCK; +connect con1,localhost,root,,; +SET lock_wait_timeout= 1; +ANALYZE TABLE t; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +disconnect con1; +connection default; +UNLOCK TABLES; +DROP TABLE t; diff --git a/mysql-test/main/flush_and_binlog.test b/mysql-test/main/flush_and_binlog.test index 373b900b451..a28d8e365dd 100644 --- a/mysql-test/main/flush_and_binlog.test +++ b/mysql-test/main/flush_and_binlog.test @@ -27,3 +27,17 @@ FLUSH TABLES; --connection default --disconnect con1 unlock tables; + +--echo # Second test from MDEV-23843 + +CREATE TABLE t (a INT); +FLUSH TABLES WITH READ LOCK; +--connect (con1,localhost,root,,) +SET lock_wait_timeout= 1; +--error ER_LOCK_WAIT_TIMEOUT +ANALYZE TABLE t; +# Cleanup +--disconnect con1 +--connection default +UNLOCK TABLES; +DROP TABLE t; diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc index c9185045315..e59dffc10aa 100644 --- a/sql/sql_admin.cc +++ b/sql/sql_admin.cc @@ -1396,7 +1396,9 @@ bool Sql_cmd_analyze_table::execute(THD *thd) /* Presumably, ANALYZE and binlog writing doesn't require synchronization */ + thd->get_stmt_da()->set_overwrite_status(true); res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); + thd->get_stmt_da()->set_overwrite_status(false); } m_lex->first_select_lex()->table_list.first= first_table; m_lex->query_tables= first_table; From 676987c4a14069d415c56d0f259aaaa7ca742c23 Mon Sep 17 00:00:00 2001 From: Monty Date: Tue, 2 Mar 2021 14:08:38 +0200 Subject: [PATCH 14/19] MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE .. on table with foreign key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When doing a truncate on an Innodb under lock tables, InnoDB would rename the old table to #sql-... and recreate a new 't1' table. The table lock would still be on the #sql-table. When doing ALTER TABLE, Innodb would do the changes on the #sql table (which would disappear on close). When the SQL layer, as part of inline alter table, would close the original t1 table (#sql in InnoDB) and then reopen the t1 table, Innodb would notice that this does not match it's own (old) t1 table and generate an error. Fixed by adding code in truncate table that if we are under lock tables and truncating an InnoDB table, we would close, reopen and lock the table after truncate. This will remove the #sql table and ensure that lock tables is using the new empty table. Reviewer: Marko Mäkelä --- mysql-test/suite/innodb/r/truncate_foreign.result | 11 +++++++++++ mysql-test/suite/innodb/t/truncate_foreign.test | 13 +++++++++++++ sql/handler.h | 6 ++++++ sql/sql_truncate.cc | 9 +++++++++ storage/innobase/handler/ha_innodb.cc | 3 ++- 5 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb/r/truncate_foreign.result b/mysql-test/suite/innodb/r/truncate_foreign.result index fc09b74d62f..12a41860708 100644 --- a/mysql-test/suite/innodb/r/truncate_foreign.result +++ b/mysql-test/suite/innodb/r/truncate_foreign.result @@ -57,3 +57,14 @@ disconnect dml; connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; +# +# MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +# ER_CRASHED_ON_USAGE after ALTER on table with foreign key +# +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate_foreign.test b/mysql-test/suite/innodb/t/truncate_foreign.test index d9d647e69f0..1c150e5db40 100644 --- a/mysql-test/suite/innodb/t/truncate_foreign.test +++ b/mysql-test/suite/innodb/t/truncate_foreign.test @@ -67,3 +67,16 @@ connection default; SET DEBUG_SYNC = RESET; DROP TABLE child, parent; + +--echo # +--echo # MDEV-24532 Table corruption ER_NO_SUCH_TABLE_IN_ENGINE or +--echo # ER_CRASHED_ON_USAGE after ALTER on table with foreign key +--echo # + +CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a)) ENGINE=InnoDB; +ALTER TABLE t1 ADD FOREIGN KEY (b) REFERENCES t1 (a) ON UPDATE CASCADE; +LOCK TABLE t1 WRITE; +TRUNCATE TABLE t1; +ALTER TABLE t1 ADD c INT; +UNLOCK TABLES; +DROP TABLE t1; diff --git a/sql/handler.h b/sql/handler.h index 6113b748696..e0e0604176d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1419,6 +1419,12 @@ handlerton *ha_default_tmp_handlerton(THD *thd); // MySQL compatibility. Unused. #define HTON_SUPPORTS_FOREIGN_KEYS (1 << 0) //Foreign key constraint supported. +/* + Table requires and close and reopen after truncate + If the handler has HTON_CAN_RECREATE, this flag is not used +*/ +#define HTON_REQUIRES_CLOSE_AFTER_TRUNCATE (1 << 18) + class Ha_trx_info; struct THD_TRANS diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index ea4d7399ea3..7d1f630b88c 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -439,6 +439,15 @@ bool Sql_cmd_truncate_table::truncate_table(THD *thd, TABLE_LIST *table_ref) */ error= handler_truncate(thd, table_ref, FALSE); + if (error == TRUNCATE_OK && thd->locked_tables_mode && + (table_ref->table->file->ht->flags & + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE)) + { + thd->locked_tables_list.mark_table_for_reopen(thd, table_ref->table); + if (unlikely(thd->locked_tables_list.reopen_tables(thd, true))) + thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0); + } + /* All effects of a TRUNCATE TABLE operation are committed even if truncation fails in the case of non transactional tables. Thus, the diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2c51f0a9fdf..c67bf6bd607 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3702,7 +3702,8 @@ innobase_init( innobase_hton->flush_logs = innobase_flush_logs; innobase_hton->show_status = innobase_show_status; innobase_hton->flags = - HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS; + HTON_SUPPORTS_EXTENDED_KEYS | HTON_SUPPORTS_FOREIGN_KEYS | + HTON_REQUIRES_CLOSE_AFTER_TRUNCATE; #ifdef WITH_WSREP innobase_hton->abort_transaction=wsrep_abort_transaction; From 5bd994b0d56d11bf62717a84172c49ca9ed37de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 3 Mar 2021 10:13:56 +0200 Subject: [PATCH 15/19] MDEV-24811 Assertion find(table) failed with innodb_evict_tables_on_commit_debug This is a backport of commit 18535a402817d8a2b8452df0f75c15dda9199acb from 10.6. lock_release(): Implement innodb_evict_tables_on_commit_debug. Before releasing any locks, collect the identifiers of tables to be evicted. After releasing all locks, look up for the tables and evict them if it is safe to do so. trx_commit_in_memory(): Invoke trx_update_mod_tables_timestamp() before lock_release(), so that our locks will protect the tables from being evicted. --- storage/innobase/lock/lock0lock.cc | 33 ++++++++++++++++++++ storage/innobase/trx/trx0trx.cc | 50 +++--------------------------- 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index da3dba73bee..ee57a493119 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4263,6 +4263,19 @@ lock_check_dict_lock( and release possible other transactions waiting because of these locks. */ void lock_release(trx_t* trx) { +#ifdef UNIV_DEBUG + std::set to_evict; + if (innodb_evict_tables_on_commit_debug && !trx->is_recovered) +# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */ + if (!mutex_own(&dict_sys->mutex)) +# else /* this would be more proper way to do it */ + if (!trx->dict_operation_lock_mode && !trx->dict_operation) +# endif + for (trx_mod_tables_t::const_iterator it= trx->mod_tables.begin(); + it != trx->mod_tables.end(); ++it) + if (!it->first->is_temporary()) + to_evict.insert(it->first->id); +#endif ulint count = 0; trx_id_t max_trx_id = trx_sys.get_max_trx_id(); @@ -4311,6 +4324,26 @@ void lock_release(trx_t* trx) } lock_mutex_exit(); + +#ifdef UNIV_DEBUG + if (to_evict.empty()) { + return; + } + mutex_enter(&dict_sys->mutex); + lock_mutex_enter(); + for (std::set::const_iterator i = to_evict.begin(); + i != to_evict.end(); ++i) { + if (dict_table_t *table = dict_table_open_on_id( + *i, TRUE, DICT_TABLE_OP_OPEN_ONLY_IF_CACHED)) { + if (!table->get_ref_count() + && !UT_LIST_GET_LEN(table->locks)) { + dict_table_remove_from_cache_low(table, true); + } + } + } + lock_mutex_exit(); + mutex_exit(&dict_sys->mutex); +#endif } /* True if a lock mode is S or X */ diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 609ab63ff4c..90ed4141633 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1276,22 +1276,6 @@ trx_update_mod_tables_timestamp( const time_t now = time(NULL); trx_mod_tables_t::const_iterator end = trx->mod_tables.end(); -#ifdef UNIV_DEBUG -# if MYSQL_VERSION_ID >= 100405 -# define dict_sys_mutex dict_sys.mutex -# else -# define dict_sys_mutex dict_sys->mutex -# endif - - const bool preserve_tables = !innodb_evict_tables_on_commit_debug - || trx->is_recovered /* avoid trouble with XA recovery */ -# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */ - || mutex_own(&dict_sys_mutex) -# else /* this would be more proper way to do it */ - || trx->dict_operation_lock_mode || trx->dict_operation -# endif - ; -#endif for (trx_mod_tables_t::const_iterator it = trx->mod_tables.begin(); it != end; @@ -1307,30 +1291,6 @@ trx_update_mod_tables_timestamp( intrusive. */ dict_table_t* table = it->first; table->update_time = now; -#ifdef UNIV_DEBUG - if (preserve_tables || table->get_ref_count() - || UT_LIST_GET_LEN(table->locks)) { - /* do not evict when committing DDL operations - or if some other transaction is holding the - table handle */ - continue; - } - /* recheck while holding the mutex that blocks - table->acquire() */ - mutex_enter(&dict_sys_mutex); - mutex_enter(&lock_sys.mutex); - const bool do_evict = !table->get_ref_count() - && !UT_LIST_GET_LEN(table->locks); - mutex_exit(&lock_sys.mutex); - if (do_evict) { -# if MYSQL_VERSION_ID >= 100405 - dict_sys.remove(table, true); -# else - dict_table_remove_from_cache_low(table, true); -# endif - } - mutex_exit(&dict_sys_mutex); -#endif } trx->mod_tables.clear(); @@ -1398,16 +1358,10 @@ trx_commit_in_memory( while (UNIV_UNLIKELY(trx->is_referenced())) { ut_delay(srv_spin_wait_delay); } - - trx->release_locks(); - trx->id = 0; } else { ut_ad(trx->read_only || !trx->rsegs.m_redo.rseg); - trx->release_locks(); } - DEBUG_SYNC_C("after_trx_committed_in_memory"); - if (trx->read_only || !trx->rsegs.m_redo.rseg) { MONITOR_INC(MONITOR_TRX_RO_COMMIT); } else { @@ -1415,6 +1369,10 @@ trx_commit_in_memory( MONITOR_INC(MONITOR_TRX_RW_COMMIT); trx->is_recovered = false; } + + trx->release_locks(); + trx->id = 0; + DEBUG_SYNC_C("after_trx_committed_in_memory"); } ut_ad(!trx->rsegs.m_redo.undo); From aa4f76bed715ec1016260f593e9cf4a8a1a4da36 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 1 Mar 2021 23:07:12 +0530 Subject: [PATCH 16/19] MDEV-25018 [FATAL] InnoDB: Unable to read page (of a dropped tablespace) - This issue is caused by commit deadec4e689c9435e20ebb89fd8f84d3f0f90ff3 (MDEV-24569). InnoDB fails to read the change buffer bitmap page from dropped tablespace. In ibuf_bitmap_get_map_page_func(), InnoDB should fetch the page using BUF_GET_POSSIBLY_FREED mode. Callers of ibuf_bitmap_get_map_page() should be adjusted in that case. --- storage/innobase/ibuf/ibuf0ibuf.cc | 51 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index e550780a3d7..31ed11cd7eb 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -688,19 +688,15 @@ ibuf_bitmap_get_map_page_func( unsigned line, mtr_t* mtr) { - buf_block_t* block = NULL; - dberr_t err = DB_SUCCESS; - - block = buf_page_get_gen( + buf_block_t* block = buf_page_get_gen( ibuf_bitmap_page_no_calc(page_id, zip_size), - zip_size, RW_X_LATCH, NULL, BUF_GET, file, line, mtr, &err); + zip_size, RW_X_LATCH, NULL, BUF_GET_POSSIBLY_FREED, + file, line, mtr); - if (err != DB_SUCCESS) { - return NULL; + if (block) { + buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP); } - - buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP); return block; } @@ -741,9 +737,12 @@ ibuf_set_free_bits_low( #endif /* UNIV_IBUF_DEBUG */ const page_id_t id(block->page.id()); - ibuf_bitmap_page_set_bits( - ibuf_bitmap_get_map_page(id, block->zip_size(), mtr), - id, block->physical_size(), val, mtr); + if (buf_block_t* bitmap_page = ibuf_bitmap_get_map_page( + id, block->zip_size(), mtr)) { + ibuf_bitmap_page_set_bits( + bitmap_page, id, block->physical_size(), + val, mtr); + } } /************************************************************************//** @@ -887,10 +886,13 @@ ibuf_update_free_bits_zip( buf_page_make_young(&block->page); } - ibuf_bitmap_page_set_bits( - ibuf_bitmap_get_map_page(block->page.id(), block->zip_size(), - mtr), - block->page.id(), block->physical_size(), after, mtr); + if (buf_block_t* bitmap_page = ibuf_bitmap_get_map_page( + block->page.id(), block->zip_size(), mtr)) { + + ibuf_bitmap_page_set_bits( + bitmap_page, block->page.id(), + block->physical_size(), after, mtr); + } } /**********************************************************************//** @@ -3669,14 +3671,15 @@ ibuf_insert_to_index_page_low( "InnoDB: is now probably corrupt. Please run CHECK TABLE on\n" "InnoDB: that table.\n", stderr); - ib::error() << "page " << block->page.id() << ", size " - << block->physical_size() << ", bitmap bits " - << ibuf_bitmap_page_get_bits( - ibuf_bitmap_get_map_page(block->page.id(), - block->zip_size(), - mtr)->frame, - block->page.id(), block->zip_size(), - IBUF_BITMAP_FREE, mtr); + if (buf_block_t *bitmap_page = ibuf_bitmap_get_map_page( + block->page.id(), block->zip_size(), mtr)) { + + ib::error() << "page " << block->page.id() << ", size " + << block->physical_size() << ", bitmap bits " + << ibuf_bitmap_page_get_bits(bitmap_page->frame, + block->page.id(), block->zip_size(), + IBUF_BITMAP_FREE, mtr); + } ib::error() << BUG_REPORT_MSG; From fcc9f8b10cd2f497ff410b592808eedb3ee5f212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 5 Mar 2021 10:40:16 +0200 Subject: [PATCH 17/19] Remove unused HA_EXTRA_FAKE_START_STMT This is fixup for commit f06a0b5338694755842a58798bb3a9a40da78bfd. --- include/my_base.h | 6 ++---- sql/ha_partition.cc | 3 +-- storage/innobase/handler/ha_innodb.cc | 4 ---- storage/mroonga/ha_mroonga.cpp | 3 --- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index 44af7b45075..767da14b4d6 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2012, Oracle and/or its affiliates. - Copyright (c) 1995, 2018, MariaDB Corporation. + Copyright (c) 1995, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -213,9 +213,7 @@ enum ha_extra_function { /** Start writing rows during ALTER TABLE...ALGORITHM=COPY. */ HA_EXTRA_BEGIN_ALTER_COPY, /** Finish writing rows during ALTER TABLE...ALGORITHM=COPY. */ - HA_EXTRA_END_ALTER_COPY, - /** Fake the start of a statement after wsrep_load_data_splitting hack */ - HA_EXTRA_FAKE_START_STMT + HA_EXTRA_END_ALTER_COPY }; /* Compatible option, to be deleted in 6.0 */ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 9313282630f..4c4a62e7fc4 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -9060,7 +9060,6 @@ int ha_partition::extra(enum ha_extra_function operation) case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN: case HA_EXTRA_BEGIN_ALTER_COPY: case HA_EXTRA_END_ALTER_COPY: - case HA_EXTRA_FAKE_START_STMT: DBUG_RETURN(loop_partitions(extra_cb, &operation)); default: { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 76723d62761..50d7b2d2002 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -15318,10 +15318,6 @@ ha_innobase::extra( case HA_EXTRA_END_ALTER_COPY: m_prebuilt->table->skip_alter_undo = 0; break; - case HA_EXTRA_FAKE_START_STMT: - trx_register_for_2pc(m_prebuilt->trx); - m_prebuilt->sql_stat_start = true; - break; default:/* Do nothing */ ; } diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index 128bc9b3583..fdca803ad96 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -550,9 +550,6 @@ static const char *mrn_inspect_extra_function(enum ha_extra_function operation) case HA_EXTRA_END_ALTER_COPY: inspected = "HA_EXTRA_END_ALTER_COPY"; break; - case HA_EXTRA_FAKE_START_STMT: - inspected = "HA_EXTRA_FAKE_START_STMT"; - break; #ifdef MRN_HAVE_HA_EXTRA_EXPORT case HA_EXTRA_EXPORT: inspected = "HA_EXTRA_EXPORT"; From e5e0e519f433aa53c8ff12050aff2b33f9b8db7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 5 Mar 2021 12:55:46 +0200 Subject: [PATCH 18/19] MDEV-24600 fixup: Remove unused trx_register_for_2pc() --- storage/innobase/handler/ha_innodb.cc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f18461daaab..4c8b5e30093 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2384,18 +2384,6 @@ trx_is_registered_for_2pc( return(trx->is_registered == 1); } -/*********************************************************************//** -Note that a transaction has been registered with MySQL 2PC coordinator. */ -static inline -void -trx_register_for_2pc( -/*==================*/ - trx_t* trx) /* in: transaction */ -{ - trx->is_registered = 1; - ut_ad(!trx->active_commit_ordered); -} - /*********************************************************************//** Note that a transaction has been deregistered. */ static inline From f6cb9e6e2dd0fb2e29a09030e74de7946139e1f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 5 Mar 2021 12:59:07 +0200 Subject: [PATCH 19/19] Cleanup: add override qualifiers to item.h --- sql/item.h | 1815 ++++++++++++++++++++++++++-------------------------- 1 file changed, 907 insertions(+), 908 deletions(-) diff --git a/sql/item.h b/sql/item.h index 2a87081584d..d328a0ec923 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2812,7 +2812,7 @@ protected: public: Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { /* @@ -2827,8 +2827,9 @@ public: table, src, param, type() == Item::NULL_ITEM); } - bool eq(const Item *item, bool binary_cmp) const; + bool eq(const Item *item, bool binary_cmp) const override; const Type_all_attributes *get_type_all_attributes_from_const() const + override { return this; } }; @@ -2881,44 +2882,39 @@ public: Item_sp_variable(THD *thd, const LEX_CSTRING *sp_var_name); public: - bool fix_fields(THD *thd, Item **)= 0; + bool fix_fields(THD *thd, Item **) override= 0; - double val_real(); - longlong val_int(); - String *val_str(String *sp); - my_decimal *val_decimal(my_decimal *decimal_value); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to); - bool is_null(); + double val_real() override; + longlong val_int() override; + String *val_str(String *sp) override; + my_decimal *val_decimal(my_decimal *decimal_value) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override; + bool is_null() override; public: - void make_send_field(THD *thd, Send_field *field); - - inline bool const_item() const; - + void make_send_field(THD *thd, Send_field *field) override; + + bool const_item() const override { return true; } + Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { return create_tmp_field_ex_simple(root, table, src, param); } - inline int save_in_field(Field *field, bool no_conversions); - inline bool send(Protocol *protocol, st_value *buffer); - bool check_vcol_func_processor(void *arg) + inline int save_in_field(Field *field, bool no_conversions) override; + inline bool send(Protocol *protocol, st_value *buffer) override; + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(m_name.str, arg, VCOL_IMPOSSIBLE); } -}; +}; /***************************************************************************** Item_sp_variable inline implementation. *****************************************************************************/ -inline bool Item_sp_variable::const_item() const -{ - return TRUE; -} - inline int Item_sp_variable::save_in_field(Field *field, bool no_conversions) { return this_item()->save_in_field(field, no_conversions); @@ -2958,41 +2954,42 @@ public: const Type_handler *handler, uint pos_in_q= 0, uint len_in_q= 0); - bool fix_fields(THD *, Item **); - Item *this_item(); - const Item *this_item() const; - Item **this_item_addr(THD *thd, Item **); + bool fix_fields(THD *, Item **) override; + Item *this_item() override; + const Item *this_item() const override; + Item **this_item_addr(THD *thd, Item **) override; - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type) override; public: inline const LEX_CSTRING *my_name() const; inline uint get_var_idx() const; - inline enum Type type() const; - const Type_handler *type_handler() const + Type type() const override { return m_type; } + const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } - uint cols() const { return this_item()->cols(); } - Item* element_index(uint i) { return this_item()->element_index(i); } - Item** addr(uint i) { return this_item()->addr(i); } - bool check_cols(uint c); + uint cols() const override { return this_item()->cols(); } + Item* element_index(uint i) override + { return this_item()->element_index(i); } + Item** addr(uint i) override { return this_item()->addr(i); } + bool check_cols(uint c) override; private: - bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: - Item_splocal *get_item_splocal() { return this; } + Item_splocal *get_item_splocal() override { return this; } - Rewritable_query_parameter *get_rewritable_query_parameter() + Rewritable_query_parameter *get_rewritable_query_parameter() override { return this; } - Settable_routine_parameter *get_settable_routine_parameter() + Settable_routine_parameter *get_settable_routine_parameter() override { return this; } - bool append_for_log(THD *thd, String *str); - - Item *get_copy(THD *thd) { return 0; } + bool append_for_log(THD *thd, String *str) override; + + Item *get_copy(THD *) override { return nullptr; } /* Override the inherited create_field_for_create_select(), @@ -3003,7 +3000,7 @@ public: The inherited implementation would create a column based on result_type(), which is less exact. */ - Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) + Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return create_table_field_from_handler(root, table); } bool is_valid_limit_clause_variable_with_error() const @@ -3050,7 +3047,7 @@ class Item_splocal_row_field :public Item_splocal protected: LEX_CSTRING m_field_name; uint m_field_idx; - bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Item_splocal_row_field(THD *thd, const Sp_rcontext_handler *rh, @@ -3063,18 +3060,18 @@ public: m_field_name(*sp_field_name), m_field_idx(sp_field_idx) { } - bool fix_fields(THD *thd, Item **); - Item *this_item(); - const Item *this_item() const; - Item **this_item_addr(THD *thd, Item **); - bool append_for_log(THD *thd, String *str); - void print(String *str, enum_query_type query_type); + bool fix_fields(THD *thd, Item **) override; + Item *this_item() override; + const Item *this_item() const override; + Item **this_item_addr(THD *thd, Item **) override; + bool append_for_log(THD *thd, String *str) override; + void print(String *str, enum_query_type query_type) override; }; class Item_splocal_row_field_by_name :public Item_splocal_row_field { - bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: Item_splocal_row_field_by_name(THD *thd, const Sp_rcontext_handler *rh, @@ -3087,8 +3084,8 @@ public: sp_var_idx, 0 /* field index will be set later */, handler, pos_in_q, len_in_q) { } - bool fix_fields(THD *thd, Item **it); - void print(String *str, enum_query_type query_type); + bool fix_fields(THD *thd, Item **it) override; + void print(String *str, enum_query_type query_type) override; }; @@ -3106,11 +3103,6 @@ inline uint Item_splocal::get_var_idx() const return m_var_idx; } -inline enum Item::Type Item_splocal::type() const -{ - return m_type; -} - /***************************************************************************** A reference to case expression in SP, used in runtime. *****************************************************************************/ @@ -3121,13 +3113,14 @@ public: Item_case_expr(THD *thd, uint case_expr_id); public: - bool fix_fields(THD *thd, Item **); - Item *this_item(); - const Item *this_item() const; - Item **this_item_addr(THD *thd, Item **); + bool fix_fields(THD *thd, Item **) override; + Item *this_item() override; + const Item *this_item() const override; + Item **this_item_addr(THD *thd, Item **) override; - inline enum Type type() const; - const Type_handler *type_handler() const { return this_item()->type_handler(); } + Type type() const override; + const Type_handler *type_handler() const override + { return this_item()->type_handler(); } public: /* @@ -3135,8 +3128,8 @@ public: Item_case_expr can not occur in views, so here it is only for debug purposes. */ - virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd) { return 0; } + void print(String *str, enum_query_type query_type) override; + Item *get_copy(THD *) override { return nullptr; } private: uint m_case_expr_id; @@ -3172,31 +3165,28 @@ class Item_name_const : public Item_fixed_hybrid public: Item_name_const(THD *thd, Item *name_arg, Item *val); - bool fix_fields(THD *, Item **); + bool fix_fields(THD *, Item **) override; - enum Type type() const; - double val_real(); - longlong val_int(); - String *val_str(String *sp); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to); - bool is_null(); - virtual void print(String *str, enum_query_type query_type); + Type type() const override; + double val_real() override; + longlong val_int() override; + String *val_str(String *sp) override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override; + bool is_null() override; + void print(String *str, enum_query_type query_type) override; - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return value_item->type_handler(); } - bool const_item() const - { - return TRUE; - } + bool const_item() const override { return true; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { /* We can get to here when using a CURSOR for a query with NAME_CONST(): @@ -3206,20 +3196,20 @@ public: return tmp_table_field_from_field_type_maybe_null(root, table, src, param, type() == Item::NULL_ITEM); } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool no_conversions) override { return value_item->save_in_field(field, no_conversions); } - bool send(Protocol *protocol, st_value *buffer) + bool send(Protocol *protocol, st_value *buffer) override { return value_item->send(protocol, buffer); } - bool check_vcol_func_processor(void *arg) + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("name_const()", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -3229,10 +3219,10 @@ class Item_literal: public Item_basic_constant public: Item_literal(THD *thd): Item_basic_constant(thd) { } - enum Type type() const { return CONST_ITEM; } - bool check_partition_func_processor(void *int_arg) { return false;} - bool const_item() const { return true; } - bool basic_const_item() const { return true; } + Type type() const override { return CONST_ITEM; } + bool check_partition_func_processor(void *) override { return false;} + bool const_item() const override { return true; } + bool basic_const_item() const override { return true; } }; @@ -3240,8 +3230,8 @@ class Item_num: public Item_literal { public: Item_num(THD *thd): Item_literal(thd) { collation= DTCollation_numeric(); } - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate); } @@ -3267,9 +3257,9 @@ public: Item_fixed_hybrid(thd, item), result_field(item->result_field) {} ~Item_result_field() {} /* Required with gcc 2.95 */ - Field *get_tmp_table_field() { return result_field; } + Field *get_tmp_table_field() override { return result_field; } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { DBUG_ASSERT(fixed); const Type_handler *h= type_handler()->type_handler_for_tmp_table(this); @@ -3281,14 +3271,14 @@ public: Item_variance_field which work when only temporary table left, so theu return table map of the temporary table. */ - table_map used_tables() const { return 1; } - bool is_result_field() { return true; } - void save_in_result_field(bool no_conversions) + table_map used_tables() const override { return 1; } + bool is_result_field() override { return true; } + void save_in_result_field(bool no_conversions) override { save_in_field(result_field, no_conversions); } - void cleanup(); - bool check_vcol_func_processor(void *arg) { return FALSE;} + void cleanup() override; + bool check_vcol_func_processor(void *) override { return false; } }; @@ -3344,17 +3334,17 @@ public: const LEX_CSTRING &field_name_arg); Item_ident(THD *thd, Item_ident *item); Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING &field_name_arg); - const char *full_name() const; - void cleanup(); + const char *full_name() const override; + void cleanup() override; st_select_lex *get_depended_from() const; - bool remove_dependence_processor(void * arg); - virtual void print(String *str, enum_query_type query_type); - virtual bool change_context_processor(void *cntx) + bool remove_dependence_processor(void * arg) override; + void print(String *str, enum_query_type query_type) override; + bool change_context_processor(void *cntx) override { context= (Name_resolution_context *)cntx; return FALSE; } /** Collect outer references */ - virtual bool collect_outer_ref_processor(void *arg); + bool collect_outer_ref_processor(void *arg) override; friend bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator *it, @@ -3403,62 +3393,61 @@ public: reset_field() before fix_fields() for all fields created this way. */ Item_field(THD *thd, Field *field); - enum Type type() const { return FIELD_ITEM; } - bool eq(const Item *item, bool binary_cmp) const; - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - String *val_str(String*); - void save_result(Field *to); - double val_result(); - longlong val_int_result(); - bool val_native(THD *thd, Native *to); - bool val_native_result(THD *thd, Native *to); - String *str_result(String* tmp); - my_decimal *val_decimal_result(my_decimal *); - bool val_bool_result(); - bool is_null_result(); - bool is_json_type(); - bool send(Protocol *protocol, st_value *buffer); - Load_data_outvar *get_load_data_outvar() - { - return this; - } - bool load_data_set_null(THD *thd, const Load_data_param *param) + Type type() const override { return FIELD_ITEM; } + bool eq(const Item *item, bool binary_cmp) const override; + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *) override; + String *val_str(String*) override; + void save_result(Field *to) override; + double val_result() override; + longlong val_int_result() override; + bool val_native(THD *thd, Native *to) override; + bool val_native_result(THD *thd, Native *to) override; + String *str_result(String* tmp) override; + my_decimal *val_decimal_result(my_decimal *) override; + bool val_bool_result() override; + bool is_null_result() override; + bool is_json_type() override; + bool send(Protocol *protocol, st_value *buffer) override; + Load_data_outvar *get_load_data_outvar() override { return this; } + bool load_data_set_null(THD *thd, const Load_data_param *param) override { return field->load_data_set_null(thd); } bool load_data_set_value(THD *thd, const char *pos, uint length, - const Load_data_param *param) + const Load_data_param *param) override { field->load_data_set_value(pos, length, param->charset()); return false; } - bool load_data_set_no_data(THD *thd, const Load_data_param *param); - void load_data_print_for_log_event(THD *thd, String *to) const; - bool load_data_add_outvar(THD *thd, Load_data_param *param) const + bool load_data_set_no_data(THD *thd, const Load_data_param *param) override; + void load_data_print_for_log_event(THD *thd, String *to) const override; + bool load_data_add_outvar(THD *thd, Load_data_param *param) const override { return param->add_outvar_field(thd, field); } - uint load_data_fixed_length() const + uint load_data_fixed_length() const override { return field->field_length; } void reset_field(Field *f); - bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); - void make_send_field(THD *thd, Send_field *tmp_field); - int save_in_field(Field *field,bool no_conversions); - void save_org_in_field(Field *field, fast_field_copier optimizer_data); - fast_field_copier setup_fast_field_copier(Field *field); - table_map used_tables() const; - table_map all_used_tables() const; - const Type_handler *type_handler() const + bool fix_fields(THD *, Item **) override; + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) + override; + void make_send_field(THD *thd, Send_field *tmp_field) override; + int save_in_field(Field *field,bool no_conversions) override; + void save_org_in_field(Field *field, fast_field_copier optimizer_data) + override; + fast_field_copier setup_fast_field_copier(Field *field) override; + table_map used_tables() const override; + table_map all_used_tables() const override; + const Type_handler *type_handler() const override { const Type_handler *handler= field->type_handler(); return handler->type_handler_for_item_field(); } - const Type_handler *real_type_handler() const + const Type_handler *real_type_handler() const override { if (field->is_created_from_null_item) return &type_handler_null; @@ -3469,23 +3458,24 @@ public: const Tmp_field_param *param); Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param); - const TYPELIB *get_typelib() const { return field->get_typelib(); } - enum_monotonicity_info get_monotonicity_info() const + const Tmp_field_param *param) override; + const TYPELIB *get_typelib() const override { return field->get_typelib(); } + enum_monotonicity_info get_monotonicity_info() const override { return MONOTONIC_STRICT_INCREASING; } - Sql_mode_dependency value_depends_on_sql_mode() const + Sql_mode_dependency value_depends_on_sql_mode() const override { return Sql_mode_dependency(0, field->value_depends_on_sql_mode()); } - longlong val_int_endpoint(bool left_endp, bool *incl_endp); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate); - longlong val_datetime_packed(THD *thd); - longlong val_time_packed(THD *thd); - bool is_null() { return field->is_null(); } - void update_null_value(); + longlong val_int_endpoint(bool left_endp, bool *incl_endp) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + bool get_date_result(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) + override; + longlong val_datetime_packed(THD *thd) override; + longlong val_time_packed(THD *thd) override; + bool is_null() override { return field->is_null(); } + void update_null_value() override; void update_table_bitmaps() { if (field && field->table) @@ -3496,13 +3486,13 @@ public: tab->mark_column_with_deps(field); } } - void update_used_tables() + void update_used_tables() override { update_table_bitmaps(); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, - COND_EQUAL **cond_equal_ref) + COND_EQUAL **cond_equal_ref) override { /* normilize_cond() replaced all conditions of type @@ -3521,28 +3511,28 @@ public: return Item_ident::build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } - bool is_result_field() { return false; } - void save_in_result_field(bool no_conversions); - Item *get_tmp_table_item(THD *thd); - bool find_not_null_fields(table_map allowed); - bool collect_item_field_processor(void * arg); - bool unknown_splocal_processor(void *arg); - bool add_field_to_set_processor(void * arg); - bool find_item_in_field_list_processor(void *arg); - bool register_field_in_read_map(void *arg); - bool register_field_in_write_map(void *arg); - bool register_field_in_bitmap(void *arg); - bool check_partition_func_processor(void *int_arg) {return FALSE;} - bool post_fix_fields_part_expr_processor(void *bool_arg); - bool check_valid_arguments_processor(void *bool_arg); - bool check_field_expression_processor(void *arg); - bool enumerate_field_refs_processor(void *arg); - bool update_table_bitmaps_processor(void *arg); - bool switch_to_nullable_fields_processor(void *arg); - bool update_vcol_processor(void *arg); - bool rename_fields_processor(void *arg); - bool check_vcol_func_processor(void *arg); - bool set_fields_as_dependent_processor(void *arg) + bool is_result_field() override { return false; } + void save_in_result_field(bool no_conversions) override; + Item *get_tmp_table_item(THD *thd) override; + bool find_not_null_fields(table_map allowed) override; + bool collect_item_field_processor(void * arg) override; + bool unknown_splocal_processor(void *arg) override; + bool add_field_to_set_processor(void * arg) override; + bool find_item_in_field_list_processor(void *arg) override; + bool register_field_in_read_map(void *arg) override; + bool register_field_in_write_map(void *arg) override; + bool register_field_in_bitmap(void *arg) override; + bool check_partition_func_processor(void *) override {return false;} + bool post_fix_fields_part_expr_processor(void *bool_arg) override; + bool check_valid_arguments_processor(void *bool_arg) override; + bool check_field_expression_processor(void *arg) override; + bool enumerate_field_refs_processor(void *arg) override; + bool update_table_bitmaps_processor(void *arg) override; + bool switch_to_nullable_fields_processor(void *arg) override; + bool update_vcol_processor(void *arg) override; + bool rename_fields_processor(void *arg) override; + bool check_vcol_func_processor(void *arg) override; + bool set_fields_as_dependent_processor(void *arg) override { if (!(used_tables() & OUTER_REF_TABLE_BIT)) { @@ -3551,38 +3541,39 @@ public: } return 0; } - void cleanup(); - Item_equal *get_item_equal() { return item_equal; } - void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; } - Item_equal *find_item_equal(COND_EQUAL *cond_equal); - Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *); - Item *replace_equal_field(THD *thd, uchar *arg); - uint32 max_display_length() const { return field->max_display_length(); } - Item_field *field_for_view_update() { return this; } + void cleanup() override; + Item_equal *get_item_equal() override { return item_equal; } + void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } + Item_equal *find_item_equal(COND_EQUAL *cond_equal) override; + Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; + Item *replace_equal_field(THD *thd, uchar *arg) override; + uint32 max_display_length() const override + { return field->max_display_length(); } + Item_field *field_for_view_update() override { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); - virtual Item *update_value_transformer(THD *thd, uchar *select_arg); - Item *derived_field_transformer_for_having(THD *thd, uchar *arg); - Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); - Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); - Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); - virtual void print(String *str, enum_query_type query_type); - bool excl_dep_on_table(table_map tab_map); - bool excl_dep_on_grouping_fields(st_select_lex *sel); - bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); - bool cleanup_excluding_fields_processor(void *arg) + Item *update_value_transformer(THD *thd, uchar *select_arg) override; + Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override; + Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) override; + void print(String *str, enum_query_type query_type) override; + bool excl_dep_on_table(table_map tab_map) override; + bool excl_dep_on_grouping_fields(st_select_lex *sel) override; + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override; + bool cleanup_excluding_fields_processor(void *arg) override { return field ? 0 : cleanup_processor(arg); } - bool cleanup_excluding_const_fields_processor(void *arg) + bool cleanup_excluding_const_fields_processor(void *arg) override { return field && const_item() ? 0 : cleanup_processor(arg); } - - Item *get_copy(THD *thd) + + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - bool is_outer_field() const + bool is_outer_field() const override { DBUG_ASSERT(fixed); return field->table->pos_in_table_list->outer_join; } - bool check_index_dependence(void *arg); + bool check_index_dependence(void *arg) override; friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; @@ -3600,14 +3591,15 @@ public: :Item_field(thd, field), Item_args() { } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - const Type_handler *type_handler() const { return &type_handler_row; } - uint cols() const { return arg_count; } - Item* element_index(uint i) { return arg_count ? args[i] : this; } - Item** addr(uint i) { return arg_count ? args + i : NULL; } - bool check_cols(uint c) + const Type_handler *type_handler() const override + { return &type_handler_row; } + uint cols() const override { return arg_count; } + Item* element_index(uint i) override { return arg_count ? args[i] : this; } + Item** addr(uint i) override { return arg_count ? args + i : NULL; } + bool check_cols(uint c) override { if (cols() != c) { @@ -3656,7 +3648,7 @@ public: Item_temptable_field(THD *thd, Item_field *item) : Item_field(thd, item) {}; - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type) override; }; @@ -3672,34 +3664,36 @@ public: name.length= strlen(name.str); collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } - enum Type type() const { return NULL_ITEM; } - bool vcol_assignment_allowed_value() const { return true; } - double val_real(); - longlong val_int(); - String *val_str(String *str); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - longlong val_datetime_packed(THD *); - longlong val_time_packed(THD *); - int save_in_field(Field *field, bool no_conversions); - int save_safe_in_field(Field *field); - bool send(Protocol *protocol, st_value *buffer); - const Type_handler *type_handler() const { return &type_handler_null; } - bool basic_const_item() const { return 1; } - Item *clone_item(THD *thd); - bool const_is_null() const { return true; } - bool is_null() { return 1; } + Type type() const override { return NULL_ITEM; } + bool vcol_assignment_allowed_value() const override { return true; } + double val_real() override; + longlong val_int() override; + String *val_str(String *str) override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + longlong val_datetime_packed(THD *) override; + longlong val_time_packed(THD *) override; + int save_in_field(Field *field, bool no_conversions) override; + int save_safe_in_field(Field *field) override; + bool send(Protocol *protocol, st_value *buffer) override; + const Type_handler *type_handler() const override + { return &type_handler_null; } + bool basic_const_item() const override { return true; } + Item *clone_item(THD *thd) override; + bool const_is_null() const override { return true; } + bool is_null() override { return true; } - virtual inline void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type) override { str->append(STRING_WITH_LEN("NULL")); } - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - bool check_partition_func_processor(void *int_arg) {return FALSE;} + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; + bool check_partition_func_processor(void *) override { return false; } Item_basic_constant *make_string_literal_concat(THD *thd, - const LEX_CSTRING *); - Item *get_copy(THD *thd) + const LEX_CSTRING *) + override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -3708,25 +3702,25 @@ class Item_null_result :public Item_null public: Field *result_field; Item_null_result(THD *thd): Item_null(thd), result_field(0) {} - bool is_result_field() { return result_field != 0; } - const Type_handler *type_handler() const + bool is_result_field() override { return result_field != 0; } + const Type_handler *type_handler() const override { if (result_field) return result_field->type_handler(); return &type_handler_null; } - Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + Field *create_tmp_field_ex(MEM_ROOT *, TABLE *, Tmp_field_src *, + const Tmp_field_param *) override { DBUG_ASSERT(0); return NULL; } - void save_in_result_field(bool no_conversions) + void save_in_result_field(bool no_conversions) override { save_in_field(result_field, no_conversions); } - bool check_partition_func_processor(void *int_arg) {return TRUE;} - bool check_vcol_func_processor(void *arg) + bool check_partition_func_processor(void *) override { return true; } + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); } @@ -3910,7 +3904,7 @@ class Item_param :public Item_basic_value, const String *value_query_val_str(THD *thd, String* str) const; Item *value_clone_item(THD *thd); - bool is_evaluable_expression() const; + bool is_evaluable_expression() const override; bool can_return_value() const; public: @@ -3919,10 +3913,10 @@ public: */ enum enum_indicator_type indicator; - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } - bool vcol_assignment_allowed_value() const + bool vcol_assignment_allowed_value() const override { switch (state) { case NULL_VALUE: @@ -3940,7 +3934,7 @@ public: Item_param(THD *thd, const LEX_CSTRING *name_arg, uint pos_in_query_arg, uint len_in_query_arg); - enum Type type() const + Type type() const override { // Don't pretend to be a constant unless value for this item is set. switch (state) { @@ -3955,13 +3949,13 @@ public: return PARAM_ITEM; } - bool is_order_clause_position() const + bool is_order_clause_position() const override { return state == SHORT_DATA_VALUE && type_handler()->is_order_clause_position_type(); } - const Item_const *get_item_const() const + const Item_const *get_item_const() const override { switch (state) { case SHORT_DATA_VALUE: @@ -3976,47 +3970,47 @@ public: return NULL; } - bool const_is_null() const { return state == NULL_VALUE; } + bool const_is_null() const override { return state == NULL_VALUE; } bool can_return_const_value(Item_result type) const { return can_return_value() && value.type_handler()->cmp_type() == type && type_handler()->cmp_type() == type; } - const longlong *const_ptr_longlong() const + const longlong *const_ptr_longlong() const override { return can_return_const_value(INT_RESULT) ? &value.integer : NULL; } - const double *const_ptr_double() const + const double *const_ptr_double() const override { return can_return_const_value(REAL_RESULT) ? &value.real : NULL; } - const my_decimal *const_ptr_my_decimal() const + const my_decimal *const_ptr_my_decimal() const override { return can_return_const_value(DECIMAL_RESULT) ? &value.m_decimal : NULL; } - const MYSQL_TIME *const_ptr_mysql_time() const + const MYSQL_TIME *const_ptr_mysql_time() const override { return can_return_const_value(TIME_RESULT) ? &value.time : NULL; } - const String *const_ptr_string() const + const String *const_ptr_string() const override { return can_return_const_value(STRING_RESULT) ? &value.m_string : NULL; } - double val_real() + double val_real() override { return can_return_value() ? value.val_real() : 0e0; } - longlong val_int() + longlong val_int() override { return can_return_value() ? value.val_int(this) : 0; } - my_decimal *val_decimal(my_decimal *dec) + my_decimal *val_decimal(my_decimal *dec) override { return can_return_value() ? value.val_decimal(dec, this) : NULL; } - String *val_str(String *str) + String *val_str(String *str) override { return can_return_value() ? value.val_str(str, this) : NULL; } - bool get_date(THD *thd, MYSQL_TIME *tm, date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to) + bool get_date(THD *thd, MYSQL_TIME *tm, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override { return Item_param::type_handler()->Item_param_val_native(thd, this, to); } - int save_in_field(Field *field, bool no_conversions); + int save_in_field(Field *field, bool no_conversions) override; void set_default(); void set_ignore(); @@ -4092,18 +4086,18 @@ public: so no one will use parameters value in fix_fields still parameter is constant during execution. */ - bool const_item() const + bool const_item() const override { return state != NO_VALUE; } - virtual table_map used_tables() const + table_map used_tables() const override { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } - virtual void print(String *str, enum_query_type query_type); - bool is_null() + void print(String *str, enum_query_type query_type) override; + bool is_null() override { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } - bool basic_const_item() const; + bool basic_const_item() const override; bool has_no_value() const { return state == NO_VALUE; @@ -4127,18 +4121,18 @@ public: constant, assert otherwise. This method is called only if basic_const_item returned TRUE. */ - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - Item *clone_item(THD *thd); + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; + Item *clone_item(THD *thd) override; void set_param_type_and_swap_value(Item_param *from); - Rewritable_query_parameter *get_rewritable_query_parameter() + Rewritable_query_parameter *get_rewritable_query_parameter() override { return this; } - Settable_routine_parameter *get_settable_routine_parameter() - { return m_is_settable_routine_parameter ? this : NULL; } + Settable_routine_parameter *get_settable_routine_parameter() override + { return m_is_settable_routine_parameter ? this : nullptr; } - bool append_for_log(THD *thd, String *str); - bool check_vcol_func_processor(void *int_arg) {return FALSE;} - Item *get_copy(THD *thd) { return 0; } + bool append_for_log(THD *thd, String *str) override; + bool check_vcol_func_processor(void *) override { return false; } + Item *get_copy(THD *) override { return nullptr; } bool add_as_clone(THD *thd); void sync_clones(); @@ -4147,16 +4141,16 @@ public: private: void invalid_default_param() const; - virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; - virtual void set_out_param_info(Send_field *info); + void set_out_param_info(Send_field *info) override; public: - virtual const Send_field *get_out_param_info() const; + const Send_field *get_out_param_info() const override; - Item_param *get_item_param() { return this; } + Item_param *get_item_param() override { return this; } - virtual void make_send_field(THD *thd, Send_field *field); + void make_send_field(THD *thd, Send_field *field) override; private: Send_field *m_out_param_info; @@ -4197,24 +4191,24 @@ public: unsigned_flag= flag; } Item_int(THD *thd, const char *str_arg, size_t length=64); - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return type_handler_long_or_longlong(); } - Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) + Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table) override { return tmp_table_field_from_field_type(root, table); } - const longlong *const_ptr_longlong() const { return &value; } - longlong val_int() { return value; } - longlong val_int_min() const { return value; } - double val_real() { return (double) value; } - my_decimal *val_decimal(my_decimal *); - String *val_str(String*); - int save_in_field(Field *field, bool no_conversions); - bool is_order_clause_position() const { return true; } - Item *clone_item(THD *thd); - virtual void print(String *str, enum_query_type query_type); - Item *neg(THD *thd); - uint decimal_precision() const + const longlong *const_ptr_longlong() const override { return &value; } + longlong val_int() override { return value; } + longlong val_int_min() const override { return value; } + double val_real() override { return (double) value; } + my_decimal *val_decimal(my_decimal *) override; + String *val_str(String*) override; + int save_in_field(Field *field, bool no_conversions) override; + bool is_order_clause_position() const override { return true; } + Item *clone_item(THD *thd) override; + void print(String *str, enum_query_type query_type) override; + Item *neg(THD *thd) override; + uint decimal_precision() const override { return (uint) (max_length - MY_TEST(value < 0)); } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4230,13 +4224,13 @@ public: Item_bool(THD *thd, const char *str_arg, longlong i): Item_int(thd, str_arg, i, 1) {} Item_bool(THD *thd, bool i) :Item_int(thd, (longlong) i, 1) { } - bool is_bool_literal() const { return true; } - Item *neg_transformer(THD *thd); - const Type_handler *type_handler() const + bool is_bool_literal() const override { return true; } + Item *neg_transformer(THD *thd) override; + const Type_handler *type_handler() const override { return &type_handler_bool; } - const Type_handler *fixed_type_handler() const + const Type_handler *fixed_type_handler() const override { return &type_handler_bool; } - void quick_fix_field() + void quick_fix_field() override { /* We can get here when Item_bool is created instead of a constant @@ -4267,11 +4261,11 @@ protected: MYSQL_TIME ltime; public: Item_datetime(THD *thd): Item_int(thd, 0) { unsigned_flag=0; } - int save_in_field(Field *field, bool no_conversions); - longlong val_int(); - double val_real() { return (double)val_int(); } + int save_in_field(Field *field, bool no_conversions) override; + longlong val_int() override; + double val_real() override { return (double)val_int(); } void set(longlong packed, enum_mysql_timestamp_type ts_type); - bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate) override { *to= ltime; return false; @@ -4294,23 +4288,26 @@ public: Item_decimal(THD *thd, double val, int precision, int scale); Item_decimal(THD *thd, const uchar *bin, int precision, int scale); - const Type_handler *type_handler() const { return &type_handler_newdecimal; } - longlong val_int() { return decimal_value.to_longlong(unsigned_flag); } - double val_real() { return decimal_value.to_double(); } - String *val_str(String *to) { return decimal_value.to_string(to); } - my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } - const my_decimal *const_ptr_my_decimal() const { return &decimal_value; } - int save_in_field(Field *field, bool no_conversions); - Item *clone_item(THD *thd); - virtual void print(String *str, enum_query_type query_type) + const Type_handler *type_handler() const override + { return &type_handler_newdecimal; } + longlong val_int() override + { return decimal_value.to_longlong(unsigned_flag); } + double val_real() override { return decimal_value.to_double(); } + String *val_str(String *to) override { return decimal_value.to_string(to); } + my_decimal *val_decimal(my_decimal *val) override { return &decimal_value; } + const my_decimal *const_ptr_my_decimal() const override + { return &decimal_value; } + int save_in_field(Field *field, bool no_conversions) override; + Item *clone_item(THD *thd) override; + void print(String *str, enum_query_type query_type) override { decimal_value.to_string(&str_value); str->append(str_value); } - Item *neg(THD *thd); - uint decimal_precision() const { return decimal_value.precision(); } + Item *neg(THD *thd) override; + uint decimal_precision() const override { return decimal_value.precision(); } void set_decimal_value(my_decimal *value_par); - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4334,11 +4331,12 @@ public: { decimals= (uint8) decimal_par; } - int save_in_field(Field *field, bool no_conversions); - const Type_handler *type_handler() const { return &type_handler_double; } - const double *const_ptr_double() const { return &value; } - double val_real() { return value; } - longlong val_int() + int save_in_field(Field *field, bool no_conversions) override; + const Type_handler *type_handler() const override + { return &type_handler_double; } + const double *const_ptr_double() const override { return &value; } + double val_real() override { return value; } + longlong val_int() override { if (value <= (double) LONGLONG_MIN) { @@ -4350,12 +4348,12 @@ public: } return (longlong) rint(value); } - String *val_str(String*); - my_decimal *val_decimal(my_decimal *); - Item *clone_item(THD *thd); - Item *neg(THD *thd); - virtual void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd) + String *val_str(String*) override; + my_decimal *val_decimal(my_decimal *) override; + Item *clone_item(THD *thd) override; + Item *neg(THD *thd) override; + void print(String *str, enum_query_type query_type) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4369,12 +4367,12 @@ public: Item_float(thd, NullS, val_arg, decimal_par, length), func_name(str) {} - virtual inline void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type) override { str->append(func_name); } - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true, func_name); } @@ -4459,25 +4457,23 @@ public: { str_value.print(to); } - double val_real(); - longlong val_int(); - const String *const_ptr_string() const - { - return &str_value; - } - String *val_str(String*) + double val_real() override; + longlong val_int() override; + const String *const_ptr_string() const override { return &str_value; } + String *val_str(String*) override { return (String*) &str_value; } - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } - int save_in_field(Field *field, bool no_conversions); - const Type_handler *type_handler() const { return &type_handler_varchar; } - Item *clone_item(THD *thd); - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) + int save_in_field(Field *field, bool no_conversions) override; + const Type_handler *type_handler() const override + { return &type_handler_varchar; } + Item *clone_item(THD *thd) override; + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true); } @@ -4486,7 +4482,7 @@ public: str_value.append(str, length); max_length= str_value.numchars() * collation.collation->mbmaxlen; } - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type) override; /** Return TRUE if character-set-introducer was explicitly specified in the @@ -4516,10 +4512,11 @@ public: { return Item::check_well_formed_result(&str_value, send_error); } Item_basic_constant *make_string_literal_concat(THD *thd, - const LEX_CSTRING *); - Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr); + const LEX_CSTRING *) + override; + Item *make_odbc_literal(THD *thd, const LEX_CSTRING *typestr) override; - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4585,19 +4582,19 @@ public: Item_string(thd, str, tocs, conv_errors, dv, repertoire), func_name(name_par) {} - Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override { return const_charset_converter(thd, tocs, true, func_name.str); } - virtual inline void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type) override { str->append(func_name); } - bool check_partition_func_processor(void *int_arg) {return TRUE;} + bool check_partition_func_processor(void *) override { return true; } - bool check_vcol_func_processor(void *arg) + bool check_vcol_func_processor(void *arg) override { // VCOL_TIME_FUNC because the value is not constant, but does not // require fix_fields() to be re-run for every statement. return mark_unsupported_function(func_name.str, arg, VCOL_TIME_FUNC); @@ -4705,29 +4702,30 @@ public: Item_hex_hybrid(THD *thd): Item_hex_constant(thd) {} Item_hex_hybrid(THD *thd, const char *str, size_t str_length): Item_hex_constant(thd, str, str_length) {} - const Type_handler *type_handler() const { return &type_handler_hex_hybrid; } - uint decimal_precision() const; - double val_real() + const Type_handler *type_handler() const override + { return &type_handler_hex_hybrid; } + uint decimal_precision() const override; + double val_real() override { return (double) (ulonglong) Item_hex_hybrid::val_int(); } - longlong val_int() + longlong val_int() override { return longlong_from_hex_hybrid(str_value.ptr(), str_value.length()); } - my_decimal *val_decimal(my_decimal *decimal_value) + my_decimal *val_decimal(my_decimal *decimal_value) override { longlong value= Item_hex_hybrid::val_int(); int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); return decimal_value; } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool) override { field->set_notnull(); return field->store_hex_hybrid(str_value.ptr(), str_value.length()); } - void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd) + void print(String *str, enum_query_type query_type) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4747,26 +4745,26 @@ public: Item_hex_string(THD *thd): Item_hex_constant(thd) {} Item_hex_string(THD *thd, const char *str, size_t str_length): Item_hex_constant(thd, str, str_length) {} - longlong val_int() + longlong val_int() override { return longlong_from_string_with_check(&str_value); } - double val_real() - { + double val_real() override + { return double_from_string_with_check(&str_value); } - my_decimal *val_decimal(my_decimal *decimal_value) + my_decimal *val_decimal(my_decimal *decimal_value) override { return val_decimal_from_string(decimal_value); } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool) override { field->set_notnull(); return field->store(str_value.ptr(), str_value.length(), collation.collation); } - void print(String *str, enum_query_type query_type); - Item *get_copy(THD *thd) + void print(String *str, enum_query_type query_type) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4785,35 +4783,36 @@ public: Item_timestamp_literal(THD *thd) :Item_literal(thd) { } - const Type_handler *type_handler() const { return &type_handler_timestamp2; } - int save_in_field(Field *field, bool no_conversions) + const Type_handler *type_handler() const override + { return &type_handler_timestamp2; } + int save_in_field(Field *field, bool) override { Timestamp_or_zero_datetime_native native(m_value, decimals); return native.save_in_field(field, decimals); } - longlong val_int() + longlong val_int() override { return m_value.to_datetime(current_thd).to_longlong(); } - double val_real() + double val_real() override { return m_value.to_datetime(current_thd).to_double(); } - String *val_str(String *to) + String *val_str(String *to) override { return m_value.to_datetime(current_thd).to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return m_value.to_datetime(current_thd).to_decimal(to); } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { bool res= m_value.to_TIME(thd, ltime, fuzzydate); DBUG_ASSERT(!res); return res; } - bool val_native(THD *thd, Native *to) + bool val_native(THD *thd, Native *to) override { return m_value.to_native(to, decimals); } @@ -4821,7 +4820,7 @@ public: { m_value= value; } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4842,7 +4841,7 @@ public: decimals= dec_arg; } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool no_conversions) override { return save_date_in_field(field, no_conversions); } }; @@ -4881,35 +4880,36 @@ public: */ maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } - const Type_handler *type_handler() const { return &type_handler_newdate; } - void print(String *str, enum_query_type query_type); - const MYSQL_TIME *const_ptr_mysql_time() const + const Type_handler *type_handler() const override + { return &type_handler_newdate; } + void print(String *str, enum_query_type query_type) override; + const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } - Item *clone_item(THD *thd); - longlong val_int() + Item *clone_item(THD *thd) override; + longlong val_int() override { return update_null() ? 0 : cached_time.to_longlong(); } - double val_real() + double val_real() override { return update_null() ? 0 : cached_time.to_double(); } - String *val_str(String *to) + String *val_str(String *to) override { return update_null() ? 0 : cached_time.to_string(to); } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return update_null() ? 0 : cached_time.to_decimal(to); } - longlong val_datetime_packed(THD *thd) + longlong val_datetime_packed(THD *thd) override { return update_null() ? 0 : cached_time.valid_date_to_packed(); } - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); - Item *get_copy(THD *thd) + bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4929,27 +4929,30 @@ public: DBUG_ASSERT(cached_time.is_valid_time()); max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); } - const Type_handler *type_handler() const { return &type_handler_time2; } - void print(String *str, enum_query_type query_type); - const MYSQL_TIME *const_ptr_mysql_time() const + const Type_handler *type_handler() const override + { return &type_handler_time2; } + void print(String *str, enum_query_type query_type) override; + const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } - Item *clone_item(THD *thd); - longlong val_int() { return cached_time.to_longlong(); } - double val_real() { return cached_time.to_double(); } - String *val_str(String *to) { return cached_time.to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) { return cached_time.to_decimal(to); } - longlong val_time_packed(THD *thd) + Item *clone_item(THD *thd) override; + longlong val_int() override { return cached_time.to_longlong(); } + double val_real() override { return cached_time.to_double(); } + String *val_str(String *to) override + { return cached_time.to_string(to, decimals); } + my_decimal *val_decimal(my_decimal *to) override + { return cached_time.to_decimal(to); } + longlong val_time_packed(THD *thd) override { return cached_time.valid_time_to_packed(); } - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to) + bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override { return Time(thd, this).to_native(to, decimals); } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -4976,35 +4979,36 @@ public: // See the comment on maybe_null in Item_date_literal maybe_null= cached_time.check_date(TIME_NO_ZERO_DATE | TIME_NO_ZERO_IN_DATE); } - const Type_handler *type_handler() const { return &type_handler_datetime2; } - void print(String *str, enum_query_type query_type); - const MYSQL_TIME *const_ptr_mysql_time() const + const Type_handler *type_handler() const override + { return &type_handler_datetime2; } + void print(String *str, enum_query_type query_type) override; + const MYSQL_TIME *const_ptr_mysql_time() const override { return cached_time.get_mysql_time(); } - Item *clone_item(THD *thd); - longlong val_int() + Item *clone_item(THD *thd) override; + longlong val_int() override { return update_null() ? 0 : cached_time.to_longlong(); } - double val_real() + double val_real() override { return update_null() ? 0 : cached_time.to_double(); } - String *val_str(String *to) + String *val_str(String *to) override { return update_null() ? NULL : cached_time.to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return update_null() ? NULL : cached_time.to_decimal(to); } - longlong val_datetime_packed(THD *thd) + longlong val_datetime_packed(THD *thd) override { return update_null() ? 0 : cached_time.valid_datetime_to_packed(); } - bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate); - Item *get_copy(THD *thd) + bool get_date(THD *thd, MYSQL_TIME *res, date_mode_t fuzzydate) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -5223,8 +5227,9 @@ public: Used_tables_and_const_cache(item) { } Item_func_or_sum(THD *thd, List &list): Item_result_field(thd), Item_args(thd, list) { } - bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; } - bool walk(Item_processor processor, bool walk_subquery, void *arg) + bool with_subquery() const override + { DBUG_ASSERT(fixed); return m_with_subquery; } + bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (walk_args(processor, walk_subquery, arg)) return true; @@ -5248,10 +5253,10 @@ public: */ virtual const char *func_name() const= 0; virtual bool fix_length_and_dec()= 0; - bool const_item() const { return const_item_cache; } - table_map used_tables() const { return used_tables_cache; } - Item* build_clone(THD *thd); - Sql_mode_dependency value_depends_on_sql_mode() const + bool const_item() const override { return const_item_cache; } + table_map used_tables() const override { return used_tables_cache; } + Item* build_clone(THD *thd) override; + Sql_mode_dependency value_depends_on_sql_mode() const override { return Item_args::value_depends_on_sql_mode_bit_or().soft_to_hard(); } @@ -5338,55 +5343,58 @@ public: Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), With_sum_func_cache(*item), set_properties_only(0), ref(item->ref) {} - enum Type type() const { return REF_ITEM; } - enum Type real_type() const { return ref ? (*ref)->type() : - REF_ITEM; } - bool eq(const Item *item, bool binary_cmp) const - { + Type type() const override { return REF_ITEM; } + Type real_type() const override + { return ref ? (*ref)->type() : REF_ITEM; } + bool eq(const Item *item, bool binary_cmp) const override + { Item *it= ((Item *) item)->real_item(); return ref && (*ref)->eq(it, binary_cmp); } - void save_val(Field *to); - void save_result(Field *to); - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); - String *val_str(String* tmp); - bool val_native(THD *thd, Native *to); - bool is_null(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - longlong val_datetime_packed(THD *); - longlong val_time_packed(THD *); - double val_result(); - longlong val_int_result(); - String *str_result(String* tmp); - bool val_native_result(THD *thd, Native *to); - my_decimal *val_decimal_result(my_decimal *); - bool val_bool_result(); - bool is_null_result(); - bool send(Protocol *prot, st_value *buffer); - void make_send_field(THD *thd, Send_field *field); - bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); - int save_in_field(Field *field, bool no_conversions); - void save_org_in_field(Field *field, fast_field_copier optimizer_data); - fast_field_copier setup_fast_field_copier(Field *field) + void save_val(Field *to) override; + void save_result(Field *to) override; + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; + String *val_str(String* tmp) override; + bool val_native(THD *thd, Native *to) override; + bool is_null() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + longlong val_datetime_packed(THD *) override; + longlong val_time_packed(THD *) override; + double val_result() override; + longlong val_int_result() override; + String *str_result(String* tmp) override; + bool val_native_result(THD *thd, Native *to) override; + my_decimal *val_decimal_result(my_decimal *) override; + bool val_bool_result() override; + bool is_null_result() override; + bool send(Protocol *prot, st_value *buffer) override; + void make_send_field(THD *thd, Send_field *field) override; + bool fix_fields(THD *, Item **) override; + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) + override; + int save_in_field(Field *field, bool no_conversions) override; + void save_org_in_field(Field *field, fast_field_copier optimizer_data) + override; + fast_field_copier setup_fast_field_copier(Field *field) override { return (*ref)->setup_fast_field_copier(field); } - const Type_handler *type_handler() const { return (*ref)->type_handler(); } - const Type_handler *real_type_handler() const + const Type_handler *type_handler() const override + { return (*ref)->type_handler(); } + const Type_handler *real_type_handler() const override { return (*ref)->real_type_handler(); } - Field *get_tmp_table_field() + Field *get_tmp_table_field() override { return result_field ? result_field : (*ref)->get_tmp_table_field(); } - Item *get_tmp_table_item(THD *thd); + Item *get_tmp_table_item(THD *thd) override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param); - Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *); - table_map used_tables() const; - void update_used_tables(); + const Tmp_field_param *param) override; + Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; + table_map used_tables() const override; + void update_used_tables() override; COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, - COND_EQUAL **cond_equal_ref) + COND_EQUAL **cond_equal_ref) override { /* normilize_cond() replaced all conditions of type @@ -5400,129 +5408,121 @@ public: return Item_ident::build_equal_items(thd, inherited, link_item_fields, cond_equal_ref); } - bool const_item() const + bool const_item() const override { return (*ref)->const_item(); } + table_map not_null_tables() const override { - return (*ref)->const_item(); - } - table_map not_null_tables() const - { return depended_from ? 0 : (*ref)->not_null_tables(); } - bool find_not_null_fields(table_map allowed) + bool find_not_null_fields(table_map allowed) override { return depended_from ? false : (*ref)->find_not_null_fields(allowed); } - void save_in_result_field(bool no_conversions) + void save_in_result_field(bool no_conversions) override { (*ref)->save_in_field(result_field, no_conversions); } - Item *real_item() - { - return ref ? (*ref)->real_item() : this; - } - const TYPELIB *get_typelib() const + Item *real_item() override { return ref ? (*ref)->real_item() : this; } + const TYPELIB *get_typelib() const override { return ref ? (*ref)->get_typelib() : NULL; } - bool is_json_type() { return (*ref)->is_json_type(); } + bool is_json_type() override { return (*ref)->is_json_type(); } - bool walk(Item_processor processor, bool walk_subquery, void *arg) - { + bool walk(Item_processor processor, bool walk_subquery, void *arg) override + { if (ref && *ref) return (*ref)->walk(processor, walk_subquery, arg) || (this->*processor)(arg); else return FALSE; } - Item* transform(THD *thd, Item_transformer, uchar *arg); + Item* transform(THD *thd, Item_transformer, uchar *arg) override; Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, - Item_transformer transformer, uchar *arg_t); - bool enumerate_field_refs_processor(void *arg) + Item_transformer transformer, uchar *arg_t) override; + bool enumerate_field_refs_processor(void *arg) override { return (*ref)->enumerate_field_refs_processor(arg); } - void no_rows_in_result() + void no_rows_in_result() override { (*ref)->no_rows_in_result(); } - void restore_to_before_no_rows_in_result() + void restore_to_before_no_rows_in_result() override { (*ref)->restore_to_before_no_rows_in_result(); } - void print(String *str, enum_query_type query_type); - enum precedence precedence() const + void print(String *str, enum_query_type query_type) override; + enum precedence precedence() const override { return ref ? (*ref)->precedence() : DEFAULT_PRECEDENCE; } - void cleanup(); - Item_field *field_for_view_update() + void cleanup() override; + Item_field *field_for_view_update() override { return (*ref)->field_for_view_update(); } - Load_data_outvar *get_load_data_outvar() + Load_data_outvar *get_load_data_outvar() override { return (*ref)->get_load_data_outvar(); } virtual Ref_Type ref_type() { return REF; } // Row emulation: forwarding of ROW-related calls to ref - uint cols() const + uint cols() const override { return ref && result_type() == ROW_RESULT ? (*ref)->cols() : 1; } - Item* element_index(uint i) + Item* element_index(uint i) override { return ref && result_type() == ROW_RESULT ? (*ref)->element_index(i) : this; } - Item** addr(uint i) + Item** addr(uint i) override { return ref && result_type() == ROW_RESULT ? (*ref)->addr(i) : 0; } - bool check_cols(uint c) + bool check_cols(uint c) override { return ref && result_type() == ROW_RESULT ? (*ref)->check_cols(c) : Item::check_cols(c); } - bool null_inside() + bool null_inside() override { return ref && result_type() == ROW_RESULT ? (*ref)->null_inside() : 0; } - void bring_value() - { + void bring_value() override + { if (ref && result_type() == ROW_RESULT) (*ref)->bring_value(); } - bool check_vcol_func_processor(void *arg) + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("ref", arg, VCOL_IMPOSSIBLE); } - bool basic_const_item() const { return ref && (*ref)->basic_const_item(); } - bool is_outer_field() const + bool basic_const_item() const override + { return ref && (*ref)->basic_const_item(); } + bool is_outer_field() const override { DBUG_ASSERT(fixed); DBUG_ASSERT(ref); return (*ref)->is_outer_field(); } - - Item* build_clone(THD *thd); + + Item* build_clone(THD *thd) override; /** Checks if the item tree that ref points to contains a subquery. */ - virtual bool with_subquery() const - { - return (*ref)->with_subquery(); - } - Item *get_copy(THD *thd) + bool with_subquery() const override { return (*ref)->with_subquery(); } + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - bool excl_dep_on_table(table_map tab_map) - { + bool excl_dep_on_table(table_map tab_map) override + { table_map used= used_tables(); if (used & OUTER_REF_TABLE_BIT) return false; return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map); } - bool excl_dep_on_grouping_fields(st_select_lex *sel) + bool excl_dep_on_grouping_fields(st_select_lex *sel) override { return (*ref)->excl_dep_on_grouping_fields(sel); } - bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override { return (*ref)->excl_dep_on_in_subq_left_part(subq_pred); } - bool cleanup_excluding_fields_processor(void *arg) + bool cleanup_excluding_fields_processor(void *arg) override { Item *item= real_item(); if (item && item->type() == FIELD_ITEM && @@ -5530,19 +5530,19 @@ public: return 0; return cleanup_processor(arg); } - bool cleanup_excluding_const_fields_processor(void *arg) - { + bool cleanup_excluding_const_fields_processor(void *arg) override + { Item *item= real_item(); if (item && item->type() == FIELD_ITEM && ((Item_field *) item)->field && item->const_item()) return 0; return cleanup_processor(arg); } - bool with_sum_func() const { return m_with_sum_func; } - With_sum_func_cache* get_with_sum_func_cache() { return this; } - Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) + bool with_sum_func() const override { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() override { return this; } + Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) override { return (*ref)->field_transformer_for_having_pushdown(thd, arg); } - Item *remove_item_direct_ref() + Item *remove_item_direct_ref() override { *ref= (*ref)->remove_item_direct_ref(); return this; @@ -5573,28 +5573,28 @@ public: alias_name_used_arg) {} - bool fix_fields(THD *thd, Item **it) + bool fix_fields(THD *thd, Item **it) override { if ((*ref)->fix_fields_if_needed_for_scalar(thd, ref)) return TRUE; return Item_ref::fix_fields(thd, it); } - void save_val(Field *to); + void save_val(Field *to) override; /* Below we should have all val() methods as in Item_ref */ - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); - String *val_str(String* tmp); - bool val_native(THD *thd, Native *to); - bool is_null(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - longlong val_datetime_packed(THD *); - longlong val_time_packed(THD *); - virtual Ref_Type ref_type() { return DIRECT_REF; } - Item *get_copy(THD *thd) + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; + String *val_str(String* tmp) override; + bool val_native(THD *thd, Native *to) override; + bool is_null() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + longlong val_datetime_packed(THD *) override; + longlong val_time_packed(THD *) override; + Ref_Type ref_type() override { return DIRECT_REF; } + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *remove_item_direct_ref() + Item *remove_item_direct_ref() override { return (*ref)->remove_item_direct_ref(); } }; @@ -5616,7 +5616,7 @@ public: ref= (Item**)&ident; } - bool fix_fields(THD *thd, Item **it) + bool fix_fields(THD *thd, Item **it) override { DBUG_ASSERT(ident->type() == FIELD_ITEM || ident->type() == REF_ITEM); if (ident->fix_fields_if_needed_for_scalar(thd, ref)) @@ -5625,7 +5625,7 @@ public: return FALSE; } - virtual void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type query_type) override { ident->print(str, query_type); } }; @@ -5666,106 +5666,103 @@ public: Item_cache_wrapper(THD *thd, Item *item_arg); ~Item_cache_wrapper(); - enum Type type() const { return EXPR_CACHE_ITEM; } - enum Type real_type() const { return orig_item->type(); } - bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; } - bool with_sum_func() const { return m_with_sum_func; } - With_sum_func_cache* get_with_sum_func_cache() { return this; } + Type type() const override { return EXPR_CACHE_ITEM; } + Type real_type() const override { return orig_item->type(); } + bool with_subquery() const override + { DBUG_ASSERT(fixed); return m_with_subquery; } + bool with_sum_func() const override { return m_with_sum_func; } + With_sum_func_cache* get_with_sum_func_cache() override { return this; } bool set_cache(THD *thd); Expression_cache_tracker* init_tracker(MEM_ROOT *mem_root); - bool fix_fields(THD *thd, Item **it); - void cleanup(); + bool fix_fields(THD *thd, Item **it) override; + void cleanup() override; Item *get_orig_item() const { return orig_item; } /* Methods of getting value which should be cached in the cache */ - void save_val(Field *to); - double val_real(); - longlong val_int(); - String *val_str(String* tmp); - bool val_native(THD *thd, Native *to); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); - bool is_null(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool send(Protocol *protocol, st_value *buffer); - void save_org_in_field(Field *field, - fast_field_copier data __attribute__ ((__unused__))) + void save_val(Field *to) override; + double val_real() override; + longlong val_int() override; + String *val_str(String* tmp) override; + bool val_native(THD *thd, Native *to) override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; + bool is_null() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + bool send(Protocol *protocol, st_value *buffer) override; + void save_org_in_field(Field *field, fast_field_copier) override { save_val(field); } - void save_in_result_field(bool no_conversions) - { - save_val(result_field); - } - Item* get_tmp_table_item(THD *thd_arg); + void save_in_result_field(bool) override { save_val(result_field); } + Item* get_tmp_table_item(THD *thd_arg) override; /* Following methods make this item transparent as much as possible */ - virtual void print(String *str, enum_query_type query_type); - virtual const char *full_name() const { return orig_item->full_name(); } - virtual void make_send_field(THD *thd, Send_field *field) + void print(String *str, enum_query_type query_type) override; + const char *full_name() const override { return orig_item->full_name(); } + void make_send_field(THD *thd, Send_field *field) override { orig_item->make_send_field(thd, field); } - bool eq(const Item *item, bool binary_cmp) const + bool eq(const Item *item, bool binary_cmp) const override { - Item *it= ((Item *) item)->real_item(); + Item *it= const_cast(item)->real_item(); return orig_item->eq(it, binary_cmp); } void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) + override { orig_item->fix_after_pullout(new_parent, &orig_item, merge); } - int save_in_field(Field *to, bool no_conversions); - const Type_handler *type_handler() const { return orig_item->type_handler(); } - table_map used_tables() const { return orig_item->used_tables(); } - void update_used_tables() - { - orig_item->update_used_tables(); - } - bool const_item() const { return orig_item->const_item(); } - table_map not_null_tables() const { return orig_item->not_null_tables(); } - bool walk(Item_processor processor, bool walk_subquery, void *arg) + int save_in_field(Field *to, bool no_conversions) override; + const Type_handler *type_handler() const override + { return orig_item->type_handler(); } + table_map used_tables() const override { return orig_item->used_tables(); } + void update_used_tables() override { orig_item->update_used_tables(); } + bool const_item() const override { return orig_item->const_item(); } + table_map not_null_tables() const override + { return orig_item->not_null_tables(); } + bool walk(Item_processor processor, bool walk_subquery, void *arg) override { return orig_item->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } - bool enumerate_field_refs_processor(void *arg) + bool enumerate_field_refs_processor(void *arg) override { return orig_item->enumerate_field_refs_processor(arg); } - Item_field *field_for_view_update() + Item_field *field_for_view_update() override { return orig_item->field_for_view_update(); } /* Row emulation: forwarding of ROW-related calls to orig_item */ - uint cols() const + uint cols() const override { return result_type() == ROW_RESULT ? orig_item->cols() : 1; } - Item* element_index(uint i) + Item* element_index(uint i) override { return result_type() == ROW_RESULT ? orig_item->element_index(i) : this; } - Item** addr(uint i) + Item** addr(uint i) override { return result_type() == ROW_RESULT ? orig_item->addr(i) : 0; } - bool check_cols(uint c) + bool check_cols(uint c) override { return (result_type() == ROW_RESULT ? orig_item->check_cols(c) : Item::check_cols(c)); } - bool null_inside() + bool null_inside() override { return result_type() == ROW_RESULT ? orig_item->null_inside() : 0; } - void bring_value() + void bring_value() override { if (result_type() == ROW_RESULT) orig_item->bring_value(); } - bool is_expensive() { return orig_item->is_expensive(); } - bool is_expensive_processor(void *arg) + bool is_expensive() override { return orig_item->is_expensive(); } + bool is_expensive_processor(void *arg) override { return orig_item->is_expensive_processor(arg); } - bool check_vcol_func_processor(void *arg) + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *build_clone(THD *thd) { return 0; } + Item *build_clone(THD *) override { return nullptr; } }; @@ -5813,9 +5810,9 @@ public: set_null_ref_table(); } - bool fix_fields(THD *, Item **); - bool eq(const Item *item, bool binary_cmp) const; - Item *get_tmp_table_item(THD *thd) + bool fix_fields(THD *, Item **) override; + bool eq(const Item *item, bool binary_cmp) const override; + Item *get_tmp_table_item(THD *thd) override { if (const_item()) return copy_or_same(thd); @@ -5823,94 +5820,94 @@ public: item->name= name; return item; } - virtual Ref_Type ref_type() { return VIEW_REF; } - Item_equal *get_item_equal() { return item_equal; } - void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; } - Item_equal *find_item_equal(COND_EQUAL *cond_equal); - Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *); - Item *replace_equal_field(THD *thd, uchar *arg); - table_map used_tables() const; - void update_used_tables(); - table_map not_null_tables() const; - bool const_item() const { return used_tables() == 0; } + Ref_Type ref_type() override { return VIEW_REF; } + Item_equal *get_item_equal() override { return item_equal; } + void set_item_equal(Item_equal *item_eq) override { item_equal= item_eq; } + Item_equal *find_item_equal(COND_EQUAL *cond_equal) override; + Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *) override; + Item *replace_equal_field(THD *thd, uchar *arg) override; + table_map used_tables() const override; + void update_used_tables() override; + table_map not_null_tables() const override; + bool const_item() const override { return used_tables() == 0; } TABLE *get_null_ref_table() const { return null_ref_table; } - bool walk(Item_processor processor, bool walk_subquery, void *arg) - { + bool walk(Item_processor processor, bool walk_subquery, void *arg) override + { return (*ref)->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } - bool view_used_tables_processor(void *arg) + bool view_used_tables_processor(void *arg) override { TABLE_LIST *view_arg= (TABLE_LIST *) arg; if (view_arg == view) view_arg->view_used_tables|= (*ref)->used_tables(); return 0; } - bool excl_dep_on_table(table_map tab_map); - bool excl_dep_on_grouping_fields(st_select_lex *sel); - bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred); - Item *derived_field_transformer_for_having(THD *thd, uchar *arg); - Item *derived_field_transformer_for_where(THD *thd, uchar *arg); - Item *grouping_field_transformer_for_where(THD *thd, uchar *arg); - Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg); - Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg); + bool excl_dep_on_table(table_map tab_map) override; + bool excl_dep_on_grouping_fields(st_select_lex *sel) override; + bool excl_dep_on_in_subq_left_part(Item_in_subselect *subq_pred) override; + Item *derived_field_transformer_for_having(THD *thd, uchar *arg) override; + Item *derived_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) override; + Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) override; - void save_val(Field *to) + void save_val(Field *to) override { if (check_null_ref()) to->set_null(); else Item_direct_ref::save_val(to); } - double val_real() + double val_real() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_real(); } - longlong val_int() + longlong val_int() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_int(); } - String *val_str(String* tmp) + String *val_str(String* tmp) override { if (check_null_ref()) return NULL; else return Item_direct_ref::val_str(tmp); } - bool val_native(THD *thd, Native *to) + bool val_native(THD *thd, Native *to) override { if (check_null_ref()) return true; return Item_direct_ref::val_native(thd, to); } - my_decimal *val_decimal(my_decimal *tmp) + my_decimal *val_decimal(my_decimal *tmp) override { if (check_null_ref()) return NULL; else return Item_direct_ref::val_decimal(tmp); } - bool val_bool() + bool val_bool() override { if (check_null_ref()) return 0; else return Item_direct_ref::val_bool(); } - bool is_null() + bool is_null() override { if (check_null_ref()) return 1; else return Item_direct_ref::is_null(); } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { if (check_null_ref()) { @@ -5919,30 +5916,29 @@ public: } return Item_direct_ref::get_date(thd, ltime, fuzzydate); } - longlong val_time_packed(THD *thd) + longlong val_time_packed(THD *thd) override { if (check_null_ref()) return 0; else return Item_direct_ref::val_time_packed(thd); } - longlong val_datetime_packed(THD *thd) + longlong val_datetime_packed(THD *thd) override { if (check_null_ref()) return 0; else return Item_direct_ref::val_datetime_packed(thd); } - bool send(Protocol *protocol, st_value *buffer); - void save_org_in_field(Field *field, - fast_field_copier data __attribute__ ((__unused__))) + bool send(Protocol *protocol, st_value *buffer) override; + void save_org_in_field(Field *field, fast_field_copier) override { if (check_null_ref()) field->set_null(); else Item_direct_ref::save_val(field); } - void save_in_result_field(bool no_conversions) + void save_in_result_field(bool no_conversions) override { if (check_null_ref()) result_field->set_null(); @@ -5950,26 +5946,26 @@ public: Item_direct_ref::save_in_result_field(no_conversions); } - void cleanup() + void cleanup() override { null_ref_table= NULL; item_equal= NULL; Item_direct_ref::cleanup(); } /* - TODO move these val_*_result function to Item_dierct_ref (maybe) + TODO move these val_*_result function to Item_direct_ref (maybe) */ - double val_result(); - longlong val_int_result(); - String *str_result(String* tmp); - my_decimal *val_decimal_result(my_decimal *val); - bool val_bool_result(); + double val_result() override; + longlong val_int_result() override; + String *str_result(String* tmp) override; + my_decimal *val_decimal_result(my_decimal *val) override; + bool val_bool_result() override; - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *field_transformer_for_having_pushdown(THD *thd, uchar *arg) + Item *field_transformer_for_having_pushdown(THD *, uchar *) override { return this; } - Item *remove_item_direct_ref() { return this; } + Item *remove_item_direct_ref() override { return this; } }; @@ -6014,19 +6010,20 @@ public: alias_name_used_arg), outer_ref(0), in_sum_func(0), found_in_select_list(1), found_in_group_by(0) {} - void save_in_result_field(bool no_conversions) + void save_in_result_field(bool no_conversions) override { outer_ref->save_org_in_field(result_field, NULL); } - bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); - table_map used_tables() const + bool fix_fields(THD *, Item **) override; + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge) + override; + table_map used_tables() const override { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; } - table_map not_null_tables() const { return 0; } - virtual Ref_Type ref_type() { return OUTER_REF; } - bool check_inner_refs_processor(void * arg); + table_map not_null_tables() const override { return 0; } + Ref_Type ref_type() override { return OUTER_REF; } + bool check_inner_refs_processor(void * arg) override; }; @@ -6053,17 +6050,17 @@ public: const LEX_CSTRING &field_name_arg): Item_ref(thd, context_arg, item, table_name_arg, field_name_arg), owner(master) {} - void save_val(Field *to); - double val_real(); - longlong val_int(); - String* val_str(String* s); - my_decimal *val_decimal(my_decimal *); - bool val_bool(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to); - virtual void print(String *str, enum_query_type query_type); - table_map used_tables() const; - Item *get_copy(THD *thd) + void save_val(Field *to) override; + double val_real() override; + longlong val_int() override; + String* val_str(String* s) override; + my_decimal *val_decimal(my_decimal *) override; + bool val_bool() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override; + void print(String *str, enum_query_type query_type) override; + table_map used_tables() const override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6085,12 +6082,12 @@ public: { unsigned_flag= unsigned_arg; } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool no_conversions) override { return ref->save_in_field(field, no_conversions); } - Item *clone_item(THD *thd); - virtual Item *real_item() { return ref; } + Item *clone_item(THD *thd) override; + Item *real_item() override { return ref; } }; #ifdef MYSQL_SERVER @@ -6165,43 +6162,43 @@ public: This is the method that updates the cached value. It must be explicitly called by the user of this class to store the value of the original item in the cache. - */ + */ virtual void copy() = 0; Item *get_item() { return item; } /** All of the subclasses should have the same type tag */ - enum Type type() const { return COPY_STR_ITEM; } + Type type() const override { return COPY_STR_ITEM; } - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { DBUG_ASSERT(0); return NULL; } - void make_send_field(THD *thd, Send_field *field) + void make_send_field(THD *thd, Send_field *field) override { item->make_send_field(thd, field); } - table_map used_tables() const { return (table_map) 1L; } - bool const_item() const { return 0; } - bool is_null() { return null_value; } - bool check_vcol_func_processor(void *arg) + table_map used_tables() const override { return (table_map) 1L; } + bool const_item() const override { return false; } + bool is_null() override { return null_value; } + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("copy", arg, VCOL_IMPOSSIBLE); } - /* - Override the methods below as pure virtual to make sure all the + /* + Override the methods below as pure virtual to make sure all the sub-classes implement them. - */ + */ - virtual String *val_str(String*) = 0; - virtual my_decimal *val_decimal(my_decimal *) = 0; - virtual double val_real() = 0; - virtual longlong val_int() = 0; - virtual int save_in_field(Field *field, bool no_conversions) = 0; - bool walk(Item_processor processor, bool walk_subquery, void *args) + String *val_str(String*) override = 0; + my_decimal *val_decimal(my_decimal *) override = 0; + double val_real() override = 0; + longlong val_int() override = 0; + int save_in_field(Field *field, bool no_conversions) override = 0; + bool walk(Item_processor processor, bool walk_subquery, void *args) override { return (item->walk(processor, walk_subquery, args)) || (this->*processor)(args); @@ -6218,15 +6215,15 @@ class Item_copy_string : public Item_copy public: Item_copy_string(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {} - String *val_str(String*); - my_decimal *val_decimal(my_decimal *); - double val_real(); - longlong val_int(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + String *val_str(String*) override; + my_decimal *val_decimal(my_decimal *) override; + double val_real() override; + longlong val_int() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } - void copy(); - int save_in_field(Field *field, bool no_conversions); - Item *get_copy(THD *thd) + void copy() override; + int save_in_field(Field *field, bool no_conversions) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6244,15 +6241,16 @@ class Item_copy_timestamp: public Item_copy bool sane() const { return !null_value || m_value.is_zero_datetime(); } public: Item_copy_timestamp(THD *thd, Item *arg): Item_copy(thd, arg) { } - const Type_handler *type_handler() const { return &type_handler_timestamp2; } - void copy() + const Type_handler *type_handler() const override + { return &type_handler_timestamp2; } + void copy() override { Timestamp_or_zero_datetime_native_null tmp(current_thd, item, false); null_value= tmp.is_null(); m_value= tmp.is_null() ? Timestamp_or_zero_datetime() : Timestamp_or_zero_datetime(tmp); } - int save_in_field(Field *field, bool no_conversions) + int save_in_field(Field *field, bool) override { DBUG_ASSERT(sane()); if (null_value) @@ -6260,43 +6258,43 @@ public: Timestamp_or_zero_datetime_native native(m_value, decimals); return native.save_in_field(field, decimals); } - longlong val_int() + longlong val_int() override { DBUG_ASSERT(sane()); return null_value ? 0 : m_value.to_datetime(current_thd).to_longlong(); } - double val_real() + double val_real() override { DBUG_ASSERT(sane()); return null_value ? 0e0 : m_value.to_datetime(current_thd).to_double(); } - String *val_str(String *to) + String *val_str(String *to) override { DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_decimal(to); } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { DBUG_ASSERT(sane()); bool res= m_value.to_TIME(thd, ltime, fuzzydate); DBUG_ASSERT(!res); return null_value || res; } - bool val_native(THD *thd, Native *to) + bool val_native(THD *thd, Native *to) override { DBUG_ASSERT(sane()); return null_value || m_value.to_native(to, decimals); } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6358,8 +6356,8 @@ class Cached_item_str :public Cached_item_item String value,tmp_value; public: Cached_item_str(THD *thd, Item *arg); - bool cmp(void); - int cmp_read_only(); + bool cmp() override; + int cmp_read_only() override; ~Cached_item_str(); // Deallocate String:s }; @@ -6369,8 +6367,8 @@ class Cached_item_real :public Cached_item_item double value; public: Cached_item_real(Item *item_par) :Cached_item_item(item_par),value(0.0) {} - bool cmp(void); - int cmp_read_only(); + bool cmp() override; + int cmp_read_only() override; }; class Cached_item_int :public Cached_item_item @@ -6378,8 +6376,8 @@ class Cached_item_int :public Cached_item_item longlong value; public: Cached_item_int(Item *item_par) :Cached_item_item(item_par),value(0) {} - bool cmp(void); - int cmp_read_only(); + bool cmp() override; + int cmp_read_only() override; }; @@ -6388,8 +6386,8 @@ class Cached_item_decimal :public Cached_item_item my_decimal value; public: Cached_item_decimal(Item *item_par); - bool cmp(void); - int cmp_read_only(); + bool cmp() override; + int cmp_read_only() override; }; class Cached_item_field :public Cached_item @@ -6405,8 +6403,8 @@ public: /* TODO: take the memory allocation below out of the constructor. */ buff= (uchar*) thd_calloc(thd, length= field->pack_length()); } - bool cmp(void); - int cmp_read_only(); + bool cmp() override; + int cmp_read_only() override; }; class Item_default_value : public Item_field @@ -6417,58 +6415,60 @@ public: Field *cached_field= nullptr; Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) : Item_field(thd, context_arg), arg(a) {} - enum Type type() const { return DEFAULT_VALUE_ITEM; } - bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, Item **); - void cleanup(); - void print(String *str, enum_query_type query_type); - String *val_str(String *str); - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *decimal_value); - bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate); - bool val_native(THD *thd, Native *to); - bool val_native_result(THD *thd, Native *to); + Type type() const override { return DEFAULT_VALUE_ITEM; } + bool eq(const Item *item, bool binary_cmp) const override; + bool fix_fields(THD *, Item **) override; + void cleanup() override; + void print(String *str, enum_query_type query_type) override; + String *val_str(String *str) override; + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *decimal_value) override; + bool get_date(THD *thd, MYSQL_TIME *ltime,date_mode_t fuzzydate) override; + bool val_native(THD *thd, Native *to) override; + bool val_native_result(THD *thd, Native *to) override; /* Result variants */ - double val_result(); - longlong val_int_result(); - String *str_result(String* tmp); - my_decimal *val_decimal_result(my_decimal *val); - bool val_bool_result(); - bool is_null_result(); - bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + double val_result() override; + longlong val_int_result() override; + String *str_result(String* tmp) override; + my_decimal *val_decimal_result(my_decimal *val) override; + bool val_bool_result() override; + bool is_null_result() override; + bool get_date_result(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + override; - bool send(Protocol *protocol, st_value *buffer); - int save_in_field(Field *field_arg, bool no_conversions); - bool save_in_param(THD *thd, Item_param *param) + bool send(Protocol *protocol, st_value *buffer) override; + int save_in_field(Field *field_arg, bool no_conversions) override; + bool save_in_param(THD *, Item_param *param) override { // It should not be possible to have "EXECUTE .. USING DEFAULT(a)" DBUG_ASSERT(0); param->set_default(); return false; } - table_map used_tables() const; - virtual void update_used_tables() + table_map used_tables() const override; + void update_used_tables() override { if (field && field->default_value) field->default_value->expr->update_used_tables(); } - Field *get_tmp_table_field() { return 0; } - Item *get_tmp_table_item(THD *thd) { return this; } - Item_field *field_for_view_update() { return 0; } - bool update_vcol_processor(void *arg) { return 0; } - bool check_func_default_processor(void *arg) { return true; } + Field *get_tmp_table_field() override { return nullptr; } + Item *get_tmp_table_item(THD *) override { return this; } + Item_field *field_for_view_update() override { return nullptr; } + bool update_vcol_processor(void *) override { return false; } + bool check_func_default_processor(void *) override { return true; } - bool walk(Item_processor processor, bool walk_subquery, void *args) + bool walk(Item_processor processor, bool walk_subquery, void *args) override { return (arg && arg->walk(processor, walk_subquery, args)) || (this->*processor)(args); } - Item *transform(THD *thd, Item_transformer transformer, uchar *args); + Item *transform(THD *thd, Item_transformer transformer, uchar *args) + override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param); + const Tmp_field_param *param) override; }; @@ -6477,55 +6477,52 @@ class Item_contextually_typed_value_specification: public Item public: Item_contextually_typed_value_specification(THD *thd) :Item(thd) { } - enum Type type() const { return CONTEXTUALLY_TYPED_VALUE_ITEM; } - bool vcol_assignment_allowed_value() const { return true; } - bool eq(const Item *item, bool binary_cmp) const - { - return false; - } - bool is_evaluable_expression() const { return false; } - Field *create_tmp_field_ex(MEM_ROOT *root, - TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + Type type() const override { return CONTEXTUALLY_TYPED_VALUE_ITEM; } + bool vcol_assignment_allowed_value() const override { return true; } + bool eq(const Item *item, bool binary_cmp) const override { return false; } + bool is_evaluable_expression() const override { return false; } + Field *create_tmp_field_ex(MEM_ROOT *, + TABLE *, Tmp_field_src *, + const Tmp_field_param *) override { DBUG_ASSERT(0); return NULL; } - String *val_str(String *str) + String *val_str(String *str) override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } - double val_real() + double val_real() override { DBUG_ASSERT(0); // never should be called null_value= true; return 0.0; } - longlong val_int() + longlong val_int() override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } - my_decimal *val_decimal(my_decimal *decimal_value) + my_decimal *val_decimal(my_decimal *) override { DBUG_ASSERT(0); // never should be called null_value= true; return 0; } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *, MYSQL_TIME *, date_mode_t) override { DBUG_ASSERT(0); // never should be called return null_value= true; } - bool send(Protocol *protocol, st_value *buffer) + bool send(Protocol *, st_value *) override { DBUG_ASSERT(0); return true; } - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { DBUG_ASSERT(0); return &type_handler_null; @@ -6543,20 +6540,20 @@ public: Item_default_specification(THD *thd) :Item_contextually_typed_value_specification(thd) { } - void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type) override { str->append(STRING_WITH_LEN("default")); } - int save_in_field(Field *field_arg, bool no_conversions) + int save_in_field(Field *field_arg, bool) override { return field_arg->save_in_field_default_value(false); } - bool save_in_param(THD *thd, Item_param *param) + bool save_in_param(THD *, Item_param *param) override { param->set_default(); return false; } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6576,21 +6573,21 @@ public: Item_ignore_specification(THD *thd) :Item_contextually_typed_value_specification(thd) { } - void print(String *str, enum_query_type query_type) + void print(String *str, enum_query_type) override { str->append(STRING_WITH_LEN("ignore")); } - int save_in_field(Field *field_arg, bool no_conversions) + int save_in_field(Field *field_arg, bool) override { return field_arg->save_in_field_ignore_value(false); } - bool save_in_param(THD *thd, Item_param *param) + bool save_in_param(THD *, Item_param *param) override { param->set_ignore(); return false; } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6612,30 +6609,30 @@ public: Item_insert_value(THD *thd, Name_resolution_context *context_arg, Item *a) :Item_field(thd, context_arg), arg(a) {} - bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, Item **); - virtual void print(String *str, enum_query_type query_type); - int save_in_field(Field *field_arg, bool no_conversions) + bool eq(const Item *item, bool binary_cmp) const override; + bool fix_fields(THD *, Item **) override; + void print(String *str, enum_query_type query_type) override; + int save_in_field(Field *field_arg, bool no_conversions) override { return Item_field::save_in_field(field_arg, no_conversions); } - enum Type type() const { return INSERT_VALUE_ITEM; } + Type type() const override { return INSERT_VALUE_ITEM; } /* We use RAND_TABLE_BIT to prevent Item_insert_value from being treated as a constant and precalculated before execution */ - table_map used_tables() const { return RAND_TABLE_BIT; } + table_map used_tables() const override { return RAND_TABLE_BIT; } - Item_field *field_for_view_update() { return 0; } + Item_field *field_for_view_update() override { return nullptr; } - bool walk(Item_processor processor, bool walk_subquery, void *args) + bool walk(Item_processor processor, bool walk_subquery, void *args) override { return arg->walk(processor, walk_subquery, args) || (this->*processor)(args); } - bool check_partition_func_processor(void *int_arg) {return TRUE;} - bool update_vcol_processor(void *arg) { return 0; } - bool check_vcol_func_processor(void *arg) + bool check_partition_func_processor(void *) override { return true; } + bool update_vcol_processor(void *) override { return false; } + bool check_vcol_func_processor(void *arg) override { return mark_unsupported_function("value()", arg, VCOL_IMPOSSIBLE); } @@ -6678,24 +6675,24 @@ public: want_privilege(priv), table_grants(NULL), read_only (ro) {} void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); - enum Type type() const { return TRIGGER_FIELD_ITEM; } - bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, Item **); - virtual void print(String *str, enum_query_type query_type); - table_map used_tables() const { return (table_map)0L; } - Field *get_tmp_table_field() { return 0; } - Item *copy_or_same(THD *thd) { return this; } - Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } - void cleanup(); + Type type() const override { return TRIGGER_FIELD_ITEM; } + bool eq(const Item *item, bool binary_cmp) const override; + bool fix_fields(THD *, Item **) override; + void print(String *str, enum_query_type query_type) override; + table_map used_tables() const override { return (table_map)0L; } + Field *get_tmp_table_field() override { return nullptr; } + Item *copy_or_same(THD *) override { return this; } + Item *get_tmp_table_item(THD *thd) override { return copy_or_same(thd); } + void cleanup() override; private: - void set_required_privilege(bool rw); - bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + void set_required_privilege(bool rw) override; + bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override; public: - Settable_routine_parameter *get_settable_routine_parameter() + Settable_routine_parameter *get_settable_routine_parameter() override { - return (read_only ? 0 : this); + return read_only ? nullptr : this; } bool set_value(THD *thd, Item **it) @@ -6723,8 +6720,8 @@ private: */ bool read_only; public: - bool unknown_splocal_processor(void *arg) { return false; } - bool check_vcol_func_processor(void *arg); + bool unknown_splocal_processor(void *) override { return false; } + bool check_vcol_func_processor(void *arg) override; }; @@ -6791,28 +6788,28 @@ public: }; void set_used_tables(table_map map) { used_table_map= map; } - table_map used_tables() const { return used_table_map; } - enum Type type() const { return CACHE_ITEM; } + table_map used_tables() const override { return used_table_map; } + Type type() const override { return CACHE_ITEM; } - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { return create_tmp_field_ex_simple(root, table, src, param); } virtual void keep_array() {} - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type) override; bool eq_def(const Field *field) { return cached_field ? cached_field->eq_def (field) : FALSE; } - bool eq(const Item *item, bool binary_cmp) const + bool eq(const Item *item, bool binary_cmp) const override { return this == item; } - bool check_vcol_func_processor(void *arg) + bool check_vcol_func_processor(void *arg) override { if (example) { @@ -6828,7 +6825,7 @@ public: } return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } - void cleanup() + void cleanup() override { clear(); Item::cleanup(); @@ -6846,17 +6843,17 @@ public: virtual void store(Item *item); virtual Item *get_item() { return example; } virtual bool cache_value()= 0; - bool basic_const_item() const + bool basic_const_item() const override { return example && example->basic_const_item(); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } - bool is_null() { return !has_value(); } - virtual bool is_expensive() + bool is_null() override { return !has_value(); } + bool is_expensive() override { if (value_cached) return false; return example->is_expensive(); } - bool is_expensive_processor(void *arg) + bool is_expensive_processor(void *arg) override { DBUG_ASSERT(example); if (value_cached) @@ -6864,7 +6861,7 @@ public: return example->is_expensive_processor(arg); } virtual void set_null(); - bool walk(Item_processor processor, bool walk_subquery, void *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) override { if (arg == STOP_PTR) return FALSE; @@ -6872,7 +6869,7 @@ public: return TRUE; return (this->*processor)(arg); } - virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); + Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs) override; void split_sum_func2_example(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, uint flags) { @@ -6881,15 +6878,15 @@ public: Item *get_example() const { return example; } virtual Item *convert_to_basic_const_item(THD *thd) { return 0; }; - Item *derived_field_transformer_for_having(THD *thd, uchar *arg) + Item *derived_field_transformer_for_having(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } - Item *derived_field_transformer_for_where(THD *thd, uchar *arg) + Item *derived_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } - Item *grouping_field_transformer_for_where(THD *thd, uchar *arg) + Item *grouping_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } - Item *in_subq_field_transformer_for_where(THD *thd, uchar *arg) + Item *in_subq_field_transformer_for_where(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } - Item *in_subq_field_transformer_for_having(THD *thd, uchar *arg) + Item *in_subq_field_transformer_for_having(THD *thd, uchar *) override { return convert_to_basic_const_item(thd); } }; @@ -6902,16 +6899,16 @@ public: Item_cache_int(THD *thd, const Type_handler *handler): Item_cache(thd, handler), value(0) {} - double val_real(); - longlong val_int(); - String* val_str(String *str); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + double val_real() override; + longlong val_int() override; + String* val_str(String *str) override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_int(thd, ltime, fuzzydate); } - bool cache_value(); - int save_in_field(Field *field, bool no_conversions); - Item *convert_to_basic_const_item(THD *thd); - Item *get_copy(THD *thd) + bool cache_value() override; + int save_in_field(Field *field, bool no_conversions) override; + Item *convert_to_basic_const_item(THD *thd) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -6933,10 +6930,10 @@ class Item_cache_temporal: public Item_cache_int protected: Item_cache_temporal(THD *thd, const Type_handler *handler); public: - bool cache_value(); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - int save_in_field(Field *field, bool no_conversions); - bool setup(THD *thd, Item *item) + bool cache_value() override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + int save_in_field(Field *field, bool no_conversions) override; + bool setup(THD *thd, Item *item) override { if (Item_cache_int::setup(thd, item)) return true; @@ -6949,8 +6946,8 @@ public: is a constant and need not be optimized further. Important when storing packed datetime values. */ - Item *clone_item(THD *thd); - Item *convert_to_basic_const_item(THD *thd); + Item *clone_item(THD *thd) override; + Item *convert_to_basic_const_item(THD *thd) override; virtual Item *make_literal(THD *) =0; }; @@ -6960,36 +6957,36 @@ class Item_cache_time: public Item_cache_temporal public: Item_cache_time(THD *thd) :Item_cache_temporal(thd, &type_handler_time2) { } - bool cache_value(); - Item *get_copy(THD *thd) + bool cache_value() override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *make_literal(THD *); - longlong val_datetime_packed(THD *thd) + Item *make_literal(THD *) override; + longlong val_datetime_packed(THD *thd) override { Datetime::Options_cmp opt(thd); return has_value() ? Datetime(thd, this, opt).to_packed() : 0; } - longlong val_time_packed(THD *thd) + longlong val_time_packed(THD *) override { return has_value() ? value : 0; } - longlong val_int() + longlong val_int() override { return has_value() ? Time(this).to_longlong() : 0; } - double val_real() + double val_real() override { return has_value() ? Time(this).to_double() : 0; } - String *val_str(String *to) + String *val_str(String *to) override { return has_value() ? Time(this).to_string(to, decimals) : NULL; } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Time(this).to_decimal(to) : NULL; } - bool val_native(THD *thd, Native *to) + bool val_native(THD *thd, Native *to) override { return has_value() ? Time(thd, this).to_native(to, decimals) : true; } @@ -7001,30 +6998,30 @@ class Item_cache_datetime: public Item_cache_temporal public: Item_cache_datetime(THD *thd) :Item_cache_temporal(thd, &type_handler_datetime2) { } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *make_literal(THD *); - longlong val_datetime_packed(THD *thd) + Item *make_literal(THD *) override; + longlong val_datetime_packed(THD *) override { return has_value() ? value : 0; } - longlong val_time_packed(THD *thd) + longlong val_time_packed(THD *thd) override { return Time(thd, this, Time::Options_cmp(thd)).to_packed(); } - longlong val_int() + longlong val_int() override { return has_value() ? Datetime(this).to_longlong() : 0; } - double val_real() + double val_real() override { return has_value() ? Datetime(this).to_double() : 0; } - String *val_str(String *to) + String *val_str(String *to) override { return has_value() ? Datetime(this).to_string(to, decimals) : NULL; } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Datetime(this).to_decimal(to) : NULL; } @@ -7036,24 +7033,26 @@ class Item_cache_date: public Item_cache_temporal public: Item_cache_date(THD *thd) :Item_cache_temporal(thd, &type_handler_newdate) { } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - Item *make_literal(THD *); - longlong val_datetime_packed(THD *thd) + Item *make_literal(THD *) override; + longlong val_datetime_packed(THD *) override { return has_value() ? value : 0; } - longlong val_time_packed(THD *thd) + longlong val_time_packed(THD *thd) override { return Time(thd, this, Time::Options_cmp(thd)).to_packed(); } - longlong val_int() { return has_value() ? Date(this).to_longlong() : 0; } - double val_real() { return has_value() ? Date(this).to_double() : 0; } - String *val_str(String *to) + longlong val_int() override + { return has_value() ? Date(this).to_longlong() : 0; } + double val_real() override + { return has_value() ? Date(this).to_double() : 0; } + String *val_str(String *to) override { return has_value() ? Date(this).to_string(to) : NULL; } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return has_value() ? Date(this).to_decimal(to) : NULL; } @@ -7067,37 +7066,37 @@ class Item_cache_timestamp: public Item_cache public: Item_cache_timestamp(THD *thd) :Item_cache(thd, &type_handler_timestamp2) { } - Item *get_copy(THD *thd) + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } - bool cache_value(); - String* val_str(String *to) + bool cache_value() override; + String* val_str(String *to) override { return to_datetime(current_thd).to_string(to, decimals); } - my_decimal *val_decimal(my_decimal *to) + my_decimal *val_decimal(my_decimal *to) override { return to_datetime(current_thd).to_decimal(to); } - longlong val_int() + longlong val_int() override { return to_datetime(current_thd).to_longlong(); } - double val_real() + double val_real() override { return to_datetime(current_thd).to_double(); } - longlong val_datetime_packed(THD *thd) + longlong val_datetime_packed(THD *thd) override { - return to_datetime(current_thd).to_packed(); + return to_datetime(thd).to_packed(); } - longlong val_time_packed(THD *thd) + longlong val_time_packed(THD *) override { DBUG_ASSERT(0); return 0; } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); - int save_in_field(Field *field, bool no_conversions); - bool val_native(THD *thd, Native *to); + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; + int save_in_field(Field *field, bool no_conversions) override; + bool val_native(THD *thd, Native *to) override; }; @@ -7110,13 +7109,13 @@ public: :Item_cache(thd, h), value(0) {} - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_real(thd, ltime, fuzzydate); } - bool cache_value(); - Item *convert_to_basic_const_item(THD *thd); + bool cache_value() override; + Item *convert_to_basic_const_item(THD *thd) override; }; @@ -7151,18 +7150,18 @@ protected: public: Item_cache_decimal(THD *thd): Item_cache(thd, &type_handler_newdecimal) {} - double val_real(); - longlong val_int(); - String* val_str(String *str); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) + double val_real() override; + longlong val_int() override; + String* val_str(String *str) override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *to, date_mode_t mode) override { return decimal_to_datetime_with_warn(thd, VDec(this).ptr(), to, mode, NULL, NULL); } - bool cache_value(); - Item *convert_to_basic_const_item(THD *thd); - Item *get_copy(THD *thd) + bool cache_value() override; + Item *convert_to_basic_const_item(THD *thd) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -7182,17 +7181,17 @@ public: { collation.set(const_cast(item->collation)); } - double val_real(); - longlong val_int(); - String* val_str(String *); - my_decimal *val_decimal(my_decimal *); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + double val_real() override; + longlong val_int() override; + String* val_str(String *) override; + my_decimal *val_decimal(my_decimal *) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { return get_date_from_string(thd, ltime, fuzzydate); } CHARSET_INFO *charset() const { return value->charset(); }; - int save_in_field(Field *field, bool no_conversions); - bool cache_value(); - Item *convert_to_basic_const_item(THD *thd); - Item *get_copy(THD *thd) + int save_in_field(Field *field, bool no_conversions) override; + bool cache_value() override; + Item *convert_to_basic_const_item(THD *thd) override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -7231,57 +7230,57 @@ public: Item_cache_row(THD *thd): Item_cache(thd), values(0), item_count(2), save_array(0) {} - + /* - 'allocate' used only in row transformer, to preallocate space for row + 'allocate' used only in row transformer, to preallocate space for row cache. */ - bool allocate(THD *thd, uint num); + bool allocate(THD *thd, uint num) override; /* 'setup' is needed only by row => it not called by simple row subselect (only by IN subselect (in subselect optimizer)) */ - bool setup(THD *thd, Item *item); - void store(Item *item); + bool setup(THD *thd, Item *item) override; + void store(Item *item) override; void illegal_method_call(const char *); - void make_send_field(THD *thd, Send_field *) + void make_send_field(THD *, Send_field *) override { - illegal_method_call((const char*)"make_send_field"); + illegal_method_call("make_send_field"); }; - double val_real() + double val_real() override { - illegal_method_call((const char*)"val"); + illegal_method_call("val"); return 0; }; - longlong val_int() + longlong val_int() override { - illegal_method_call((const char*)"val_int"); + illegal_method_call("val_int"); return 0; }; - String *val_str(String *) + String *val_str(String *) override { - illegal_method_call((const char*)"val_str"); - return 0; + illegal_method_call("val_str"); + return nullptr; }; - my_decimal *val_decimal(my_decimal *val) + my_decimal *val_decimal(my_decimal *) override { - illegal_method_call((const char*)"val_decimal"); - return 0; + illegal_method_call("val_decimal"); + return nullptr; }; - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { - illegal_method_call((const char*)"val_decimal"); + illegal_method_call("val_decimal"); return true; } - uint cols() const { return item_count; } - Item *element_index(uint i) { return values[i]; } - Item **addr(uint i) { return (Item **) (values + i); } - bool check_cols(uint c); - bool null_inside(); - void bring_value(); - void keep_array() { save_array= 1; } - void cleanup() + uint cols() const override { return item_count; } + Item *element_index(uint i) override { return values[i]; } + Item **addr(uint i) override { return (Item **) (values + i); } + bool check_cols(uint c) override; + bool null_inside() override; + void bring_value() override; + void keep_array() override { save_array= 1; } + void cleanup() override { DBUG_ENTER("Item_cache_row::cleanup"); Item_cache::cleanup(); @@ -7291,9 +7290,9 @@ public: values= 0; DBUG_VOID_RETURN; } - bool cache_value(); - virtual void set_null(); - Item *get_copy(THD *thd) + bool cache_value() override; + void set_null() override; + Item *get_copy(THD *thd) override { return get_item_copy(thd, this); } }; @@ -7334,18 +7333,18 @@ public: common_flags= item->common_flags; } - const Type_handler *type_handler() const + const Type_handler *type_handler() const override { return Type_handler_hybrid_field_type::type_handler()-> type_handler_for_item_field(); } - const Type_handler *real_type_handler() const + const Type_handler *real_type_handler() const override { return Type_handler_hybrid_field_type::type_handler(); } - enum Type type() const { return TYPE_HOLDER; } - const TYPELIB *get_typelib() const { return enum_set_typelib; } + Type type() const override { return TYPE_HOLDER; } + const TYPELIB *get_typelib() const override { return enum_set_typelib; } /* When handling a query like this: VALUES ('') UNION VALUES( _utf16 0x0020 COLLATE utf16_bin); @@ -7361,21 +7360,21 @@ public: So st_select_lex_unit::join_union_type_attributes() could ask it to do (a) only, without (b). */ - bool const_item() const { return false; } - bool is_expensive() { return true; } - double val_real(); - longlong val_int(); - my_decimal *val_decimal(my_decimal *); - String *val_str(String*); - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate); + bool const_item() const override { return false; } + bool is_expensive() override { return true; } + double val_real() override; + longlong val_int() override; + my_decimal *val_decimal(my_decimal *) override; + String *val_str(String*) override; + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override; Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src, - const Tmp_field_param *param) + const Tmp_field_param *param) override { return Item_type_holder::real_type_handler()-> make_and_init_table_field(root, &name, Record_addr(maybe_null), *this, table); } - Item* get_copy(THD *thd) { return 0; } + Item* get_copy(THD *) override { return nullptr; } };