summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Nozdrin <alik@sun.com>2010-02-24 16:52:27 +0300
committerAlexander Nozdrin <alik@sun.com>2010-02-24 16:52:27 +0300
commitb3018e86132ff94ef7bde5d593b0c529cb10eced (patch)
tree46d0af1ca06ba43198a4cde04fa6f0a3937b0118 /sql
parent5fb9f61e4faf24cbc364108c0709fa935f2c3a09 (diff)
parent4709825c608fdcf2af29a472a61be6cfe7040d5e (diff)
downloadmariadb-git-b3018e86132ff94ef7bde5d593b0c529cb10eced.tar.gz
Manual merge from mysql-trunk-merge.
Conflicts: - client/mysql.cc - client/mysqldump.c - configure.in - mysql-test/r/csv.result - mysql-test/r/func_time.result - mysql-test/r/show_check.result - mysql-test/r/sp-error.result - mysql-test/r/sp.result - mysql-test/r/sp_trans.result - mysql-test/r/type_blob.result - mysql-test/r/type_timestamp.result - mysql-test/r/warnings.result - mysql-test/suite/rpl/r/rpl_sp.result - sql/mysql_priv.h - sql/mysqld.cc - sql/sp.cc - sql/sql_base.cc - sql/sql_table.cc - sql/sql_trigger.cc - sql/sql_view.cc - sql/table.h - sql/share/errmsg.txt - mysql-test/suite/sys_vars/r/log_bin_trust_routine_creators_basic.result
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc11
-rw-r--r--sql/ha_partition.cc33
-rw-r--r--sql/item.cc33
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_row.cc7
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/log_event.cc14
-rw-r--r--sql/log_event_old.cc2
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc55
-rw-r--r--sql/opt_range.cc15
-rw-r--r--sql/opt_sum.cc17
-rw-r--r--sql/sp_cache.cc5
-rw-r--r--sql/sp_head.cc3
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_class.cc10
-rw-r--r--sql/sql_class.h2
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_select.cc262
-rw-r--r--sql/sql_select.h39
-rw-r--r--sql/sql_table.cc42
-rw-r--r--sql/sql_trigger.cc15
-rw-r--r--sql/sql_update.cc98
-rw-r--r--sql/sql_view.cc13
-rw-r--r--sql/table.cc7
-rw-r--r--sql/table.h15
27 files changed, 470 insertions, 244 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 51bb527fc85..162299545a9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1779,11 +1779,10 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
uint store_length;
copy->str=ptr;
copy->length=pack_length();
- copy->blob_field=0;
+ copy->field= this;
if (flags & BLOB_FLAG)
{
- copy->blob_field=(Field_blob*) this;
- copy->strip=0;
+ copy->type= CACHE_BLOB;
copy->length-= table->s->blob_ptr_size;
return copy->length;
}
@@ -1791,15 +1790,15 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
(type() == MYSQL_TYPE_STRING && copy->length >= 4 &&
copy->length < 256))
{
- copy->strip=1; /* Remove end space */
+ copy->type= CACHE_STRIPPED;
store_length= 2;
}
else
{
- copy->strip=0;
+ copy->type= 0;
store_length= 0;
}
- return copy->length+ store_length;
+ return copy->length + store_length;
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 3289b529edf..877cf070abd 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -1803,13 +1803,23 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info)
void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share)
{
- handler **file_array= m_file;
+ handler **file_array;
table= table_arg;
table_share= share;
- do
+ /*
+ m_file can be NULL when using an old cached table in DROP TABLE, when the
+ table just has REMOVED PARTITIONING, see Bug#42438
+ */
+ if (m_file)
{
- (*file_array)->change_table_ptr(table_arg, share);
- } while (*(++file_array));
+ file_array= m_file;
+ DBUG_ASSERT(*file_array);
+ do
+ {
+ (*file_array)->change_table_ptr(table_arg, share);
+ } while (*(++file_array));
+ }
+
if (m_added_file && m_added_file[0])
{
/* if in middle of a drop/rename etc */
@@ -6226,7 +6236,13 @@ void ha_partition::print_error(int error, myf errflag)
thd->lex->sql_command != SQLCOM_TRUNCATE)
m_part_info->print_no_partition_found(table);
else
- m_file[m_last_part]->print_error(error, errflag);
+ {
+ /* In case m_file has not been initialized, like in bug#42438 */
+ if (m_file)
+ m_file[m_last_part]->print_error(error, errflag);
+ else
+ handler::print_error(error, errflag);
+ }
DBUG_VOID_RETURN;
}
@@ -6236,7 +6252,12 @@ bool ha_partition::get_error_message(int error, String *buf)
DBUG_ENTER("ha_partition::get_error_message");
/* Should probably look for my own errors first */
- DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf));
+
+ /* In case m_file has not been initialized, like in bug#42438 */
+ if (m_file)
+ DBUG_RETURN(m_file[m_last_part]->get_error_message(error, buf));
+ DBUG_RETURN(handler::get_error_message(error, buf));
+
}
diff --git a/sql/item.cc b/sql/item.cc
index e785f0addde..8a2c4e86dc8 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -4467,17 +4467,33 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
It's not an Item_field in the select list so we must make a new
Item_ref to point to the Item in the select list and replace the
Item_field created by the parser with the new Item_ref.
+
+ NOTE: If we are fixing an alias reference inside ORDER/GROUP BY
+ item tree, then we use new Item_ref as an intermediate value
+ to resolve referenced item only.
+ In this case the new Item_ref item is unused.
*/
Item_ref *rf= new Item_ref(context, db_name,table_name,field_name);
if (!rf)
return 1;
- thd->change_item_tree(reference, rf);
+
+ bool save_group_fix_field= thd->lex->current_select->group_fix_field;
/*
- Because Item_ref never substitutes itself with other items
- in Item_ref::fix_fields(), we can safely use the original
- pointer to it even after fix_fields()
- */
- return rf->fix_fields(thd, reference) || rf->check_cols(1);
+ No need for recursive resolving of aliases.
+ */
+ thd->lex->current_select->group_fix_field= 0;
+
+ bool ret= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
+ thd->lex->current_select->group_fix_field= save_group_fix_field;
+ if (ret)
+ return TRUE;
+
+ if (save_group_fix_field && alias_name_used)
+ thd->change_item_tree(reference, *rf->ref);
+ else
+ thd->change_item_tree(reference, rf);
+
+ return FALSE;
}
}
}
@@ -5312,7 +5328,7 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
error=field->store(nr, unsigned_flag);
}
- return error ? error : (field->table->in_use->is_error() ? 2 : 0);
+ return error ? error : (field->table->in_use->is_error() ? 1 : 0);
}
@@ -6704,7 +6720,8 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
{
if (!arg)
{
- if (field_arg->flags & NO_DEFAULT_VALUE_FLAG)
+ if (field_arg->flags & NO_DEFAULT_VALUE_FLAG &&
+ field_arg->real_type() != MYSQL_TYPE_ENUM)
{
if (field_arg->reset())
{
diff --git a/sql/item.h b/sql/item.h
index b7e6cc6c204..82f99106bc8 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -918,6 +918,7 @@ public:
virtual bool change_context_processor(uchar *context) { return 0; }
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
virtual bool is_expensive_processor(uchar *arg) { return 0; }
+ virtual bool find_item_processor(uchar *arg) { return this == (void *) arg; }
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
virtual bool cache_const_expr_analyzer(uchar **arg);
@@ -2316,7 +2317,10 @@ public:
return ref ? (*ref)->real_item() : this;
}
bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
- { return (*ref)->walk(processor, walk_subquery, arg); }
+ {
+ return (*ref)->walk(processor, walk_subquery, arg) ||
+ (this->*processor)(arg);
+ }
virtual void print(String *str, enum_query_type query_type);
bool result_as_longlong()
{
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 28de03bf049..29b37eb2bc0 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -71,7 +71,12 @@ bool Item_row::fix_fields(THD *thd, Item **ref)
Item *item= *arg;
used_tables_cache |= item->used_tables();
const_item_cache&= item->const_item() && !with_null;
- if (const_item_cache)
+ /*
+ Some subqueries transformations aren't done in the view_prepare_mode thus
+ is_null() will fail. So we skip is_null() calculation for CREATE VIEW as
+ not necessary.
+ */
+ if (const_item_cache && !thd->lex->view_prepare_mode)
{
if (item->cols() > 1)
with_null|= item->null_inside();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index a61c5d59d67..d09a9247ffa 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -3395,6 +3395,8 @@ String* Item_func_group_concat::val_str(String* str)
void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
+ /* orig_args is not filled with valid values until fix_fields() */
+ Item **pargs= fixed ? orig_args : args;
str->append(STRING_WITH_LEN("group_concat("));
if (distinct)
str->append(STRING_WITH_LEN("distinct "));
@@ -3402,7 +3404,7 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
if (i)
str->append(',');
- args[i]->print(str, query_type);
+ pargs[i]->print(str, query_type);
}
if (arg_count_order)
{
diff --git a/sql/log_event.cc b/sql/log_event.cc
index b0deee62fd7..5d20ff91442 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3275,6 +3275,18 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
const char* found_semicolon= NULL;
mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon);
log_slow_statement(thd);
+
+ /*
+ Resetting the enable_slow_log thd variable.
+
+ We need to reset it back to the opt_log_slow_slave_statements
+ value after the statement execution (and slow logging
+ is done). It might have changed if the statement was an
+ admin statement (in which case, down in mysql_parse execution
+ thd->enable_slow_log is set to the value of
+ opt_log_slow_admin_statements).
+ */
+ thd->enable_slow_log= opt_log_slow_slave_statements;
}
else
{
@@ -8900,7 +8912,7 @@ static bool record_compare(TABLE *table)
DBUG_DUMP("record[1]", table->record[1], table->s->reclength);
bool result= FALSE;
- uchar saved_x[2], saved_filler[2];
+ uchar saved_x[2]= {0, 0}, saved_filler[2]= {0, 0};
if (table->s->null_bytes > 0)
{
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index caa69269e28..dd25ba0b085 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -304,7 +304,7 @@ static bool record_compare(TABLE *table)
*/
bool result= FALSE;
- uchar saved_x[2], saved_filler[2];
+ uchar saved_x[2]= {0, 0}, saved_filler[2]= {0, 0};
if (table->s->null_bytes > 0)
{
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a006d2a07ff..660581d18df 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1192,7 +1192,7 @@ int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
- Item **ref_pointer_array);
+ Item **ref_pointer_array, ORDER *group_list= NULL);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 6bd133660b3..133bec99cda 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -5689,8 +5689,9 @@ pthread_handler_t handle_connections_namedpipes(void *arg)
create_new_thread(thd);
}
CloseHandle(connectOverlapped.hEvent);
+ DBUG_LEAVE;
decrement_handler_count();
- DBUG_RETURN(0);
+ return 0;
}
#endif /* _WIN32 */
@@ -5926,9 +5927,9 @@ error:
if (handle_connect_file_map) CloseHandle(handle_connect_file_map);
if (event_connect_answer) CloseHandle(event_connect_answer);
if (smem_event_connect_request) CloseHandle(smem_event_connect_request);
-
+ DBUG_LEAVE;
decrement_handler_count();
- DBUG_RETURN(0);
+ return 0;
}
#endif /* HAVE_SMEM */
#endif /* EMBEDDED_LIBRARY */
@@ -5973,7 +5974,7 @@ struct my_option my_long_options[]=
"Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
- "Tells the master that updates to the given database should not be logged tothe binary log.",
+ "Tells the master that updates to the given database should not be logged to the binary log.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-row-event-max-size", 0,
"The maximum size of a row-based binary log event in bytes. Rows will be "
@@ -6009,7 +6010,7 @@ struct my_option my_long_options[]=
{"collation-server", 0, "Set the default collation.",
(uchar**) &default_collation_name, (uchar**) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
- {"console", OPT_CONSOLE, "Write error output on screen; Don't remove the console window on windows.",
+ {"console", OPT_CONSOLE, "Write error output on screen; don't remove the console window on windows.",
(uchar**) &opt_console, (uchar**) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0,
0, 0, 0},
{"core-file", OPT_WANT_CORE, "Write core on errors.", 0, 0, 0, GET_NO_ARG,
@@ -6042,7 +6043,7 @@ struct my_option my_long_options[]=
0, 0, 0, 0},
#endif /* HAVE_STACK_TRACE_ON_SEGV */
/* See how it's handled in get_one_option() */
- {"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
+ {"exit-info", 'T', "Used for debugging. Use at your own risk.", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", 0, "Use system (external) locking (disabled by default). With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running. Disable with --skip-external-locking.",
(uchar**) &opt_external_locking, (uchar**) &opt_external_locking,
@@ -6050,7 +6051,7 @@ struct my_option my_long_options[]=
/* We must always support the next option to make scripts like mysqltest
easier to do */
{"gdb", 0,
- "Set up signals usable for debugging",
+ "Set up signals usable for debugging.",
(uchar**) &opt_debugging, (uchar**) &opt_debugging,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_LARGE_PAGE_OPTION
@@ -6111,7 +6112,7 @@ struct my_option my_long_options[]=
0, 0, 0, 0, 0, 0},
{"log-tc", 0,
"Path to transaction coordinator log (used for transactions that affect "
- "more than one storage engine, when binary log is disabled)",
+ "more than one storage engine, when binary log is disabled).",
(uchar**) &opt_tc_log_file, (uchar**) &opt_tc_log_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_MMAP
@@ -6141,15 +6142,17 @@ thread is in the master's binlogs.",
{"memlock", 0, "Lock mysqld in memory.", (uchar**) &locked_in_memory,
(uchar**) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"one-thread", OPT_ONE_THREAD,
- "(deprecated): Only use one thread (for debugging under Linux). Use thread-handling=no-threads instead",
+ "(Deprecated): Only use one thread (for debugging under Linux). Use "
+ "thread-handling=no-threads instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"old-style-user-limits", 0,
- "Enable old-style user limits (before 5.0.3 user resources were counted per each user+host vs. per account)",
+ "Enable old-style user limits (before 5.0.3, user resources were counted "
+ "per each user+host vs. per account).",
(uchar**) &opt_old_style_user_limits, (uchar**) &opt_old_style_user_limits,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"port-open-timeout", 0,
"Maximum time in seconds to wait for the port to become free. "
- "(Default: no wait)", (uchar**) &mysqld_port_timeout,
+ "(Default: No wait).", (uchar**) &mysqld_port_timeout,
(uchar**) &mysqld_port_timeout, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-do-db", OPT_REPLICATE_DO_DB,
"Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.%.",
@@ -6196,12 +6199,12 @@ Can't be set to 1 if --log-slave-updates is used.",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"show-slave-auth-info", 0,
- "Show user and password in SHOW SLAVE HOSTS on this master",
+ "Show user and password in SHOW SLAVE HOSTS on this master.",
(uchar**) &opt_show_slave_auth_info, (uchar**) &opt_show_slave_auth_info, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef DISABLE_GRANT_OPTIONS
{"skip-grant-tables", 0,
- "Start without grant tables. This gives all users FULL ACCESS to all tables!",
+ "Start without grant tables. This gives all users FULL ACCESS to all tables.",
(uchar**) &opt_noacl, (uchar**) &opt_noacl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
#endif
@@ -6210,7 +6213,7 @@ Can't be set to 1 if --log-slave-updates is used.",
{"skip-name-resolve", OPT_SKIP_RESOLVE,
"Don't resolve hostnames. All hostnames are IP's or 'localhost'.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"skip-new", OPT_SKIP_NEW, "Don't use new, possible wrong routines.",
+ {"skip-new", OPT_SKIP_NEW, "Don't use new, possibly wrong routines.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"skip-slave-start", 0,
"If set, slave is not autostarted.", (uchar**) &opt_skip_slave_start,
@@ -6282,7 +6285,7 @@ Can't be set to 1 if --log-slave-updates is used.",
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
- {"verbose", 'v', "Used with --help option for detailed help",
+ {"verbose", 'v', "Used with --help option for detailed help.",
(uchar**) &opt_verbose, (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
@@ -6894,27 +6897,27 @@ static void usage(void)
default_collation_name= (char*) default_charset_info->name;
print_version();
puts("\
-Copyright (C) 2000-2008 MySQL AB, by Monty and others\n\
+Copyright (C) 2000-2008 MySQL AB, by Monty and others.\n\
Copyright (C) 2008,2009 Sun Microsystems, Inc.\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
and you are welcome to modify and redistribute it under the GPL license\n\n\
-Starts the MySQL database server\n");
+Starts the MySQL database server.\n");
printf("Usage: %s [OPTIONS]\n", my_progname);
if (!opt_verbose)
- puts("\nFor more help options (several pages), use mysqld --verbose --help");
+ puts("\nFor more help options (several pages), use mysqld --verbose --help.");
else
{
#ifdef __WIN__
puts("NT and Win32 specific options:\n\
- --install Install the default service (NT)\n\
- --install-manual Install the default service started manually (NT)\n\
- --install service_name Install an optional service (NT)\n\
- --install-manual service_name Install an optional service started manually (NT)\n\
- --remove Remove the default service from the service list (NT)\n\
- --remove service_name Remove the service_name from the service list (NT)\n\
- --enable-named-pipe Only to be used for the default server (NT)\n\
- --standalone Dummy option to start as a standalone server (NT)\
+ --install Install the default service (NT).\n\
+ --install-manual Install the default service started manually (NT).\n\
+ --install service_name Install an optional service (NT).\n\
+ --install-manual service_name Install an optional service started manually (NT).\n\
+ --remove Remove the default service from the service list (NT).\n\
+ --remove service_name Remove the service_name from the service list (NT).\n\
+ --enable-named-pipe Only to be used for the default server (NT).\n\
+ --standalone Dummy option to start as a standalone server (NT).\
");
puts("");
#endif
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 68285563239..5483ed237db 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1198,11 +1198,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
if (file)
{
range_end();
- if (head->key_read)
- {
- head->key_read= 0;
- file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ head->set_keyread(FALSE);
if (free_file)
{
DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file,
@@ -1404,10 +1400,7 @@ end:
head->file= file;
/* We don't have to set 'head->keyread' here as the 'file' is unique */
if (!head->no_keyread)
- {
- head->key_read= 1;
head->mark_columns_used_by_index(index);
- }
head->prepare_for_position();
head->file= org_file;
bitmap_copy(&column_bitmap, head->read_set);
@@ -8344,7 +8337,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge");
/* We're going to just read rowids. */
- file->extra(HA_EXTRA_KEYREAD);
+ head->set_keyread(TRUE);
head->prepare_for_position();
cur_quick_it.rewind();
@@ -8420,7 +8413,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
delete unique;
doing_pk_scan= FALSE;
/* index_merge currently doesn't support "using index" at all */
- file->extra(HA_EXTRA_NO_KEYREAD);
+ head->set_keyread(FALSE);
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE);
DBUG_RETURN(result);
}
@@ -10838,7 +10831,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
int result;
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset");
- file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */
+ head->set_keyread(TRUE); /* We need only the key attributes */
if ((result= file->ha_index_init(index,1)))
DBUG_RETURN(result);
if (quick_prefix_select && quick_prefix_select->reset())
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index d85e976e9c8..ae54a462c67 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -325,11 +325,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (!error && reckey_in_range(0, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
- if (table->key_read)
- {
- table->key_read= 0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE);
table->file->ha_index_end();
if (error)
{
@@ -415,11 +411,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (!error && reckey_in_range(1, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
- if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE);
table->file->ha_index_end();
if (error)
{
@@ -880,10 +872,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
converted (for example to upper case)
*/
if (field->part_of_key.is_set(idx))
- {
- table->key_read= 1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ table->set_keyread(TRUE);
return 1;
}
}
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index a585004b1e8..09d347bf951 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -184,8 +184,9 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name)
sp_cache_invalidate()
NOTE
- This is called when a VIEW definition is modifed. We can't destroy sp_head
- objects here as one may modify VIEW definitions from prelocking-free SPs.
+ This is called when a VIEW definition is created or modified (and in some
+ other contexts). We can't destroy sp_head objects here as one may modify
+ VIEW definitions from prelocking-free SPs.
*/
void sp_cache_invalidate()
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index e50aa208798..c3cdcad70f3 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1848,6 +1848,8 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
{
bool err_status= FALSE;
uint params = m_pcont->context_var_count();
+ /* Query start time may be reset in a multi-stmt SP; keep this for later. */
+ ulonglong utime_before_sp_exec= thd->utime_after_lock;
sp_rcontext *save_spcont, *octx;
sp_rcontext *nctx = NULL;
bool save_enable_slow_log= false;
@@ -2054,6 +2056,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
delete nctx;
thd->spcont= save_spcont;
+ thd->utime_after_lock= utime_before_sp_exec;
DBUG_RETURN(err_status);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index d5a664df0d0..254b4ce7dd3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2225,6 +2225,7 @@ void wait_for_condition(THD *thd, mysql_mutex_t *mutex, mysql_cond_t *cond)
proc_info=thd->proc_info;
thd_proc_info(thd, "Waiting for table");
DBUG_ENTER("wait_for_condition");
+ DEBUG_SYNC(thd, "waiting_for_table");
if (!thd->killed)
mysql_cond_wait(cond, mutex);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b7ded3b632f..4b21bc283e2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -612,10 +612,10 @@ bool THD::handle_condition(uint sql_errno,
for (Internal_error_handler *error_handler= m_internal_handler;
error_handler;
- error_handler= m_internal_handler->m_prev_internal_handler)
+ error_handler= error_handler->m_prev_internal_handler)
{
- if (error_handler-> handle_condition(this, sql_errno, sqlstate, level, msg,
- cond_hdl))
+ if (error_handler->handle_condition(this, sql_errno, sqlstate, level, msg,
+ cond_hdl))
{
return TRUE;
}
@@ -625,10 +625,12 @@ bool THD::handle_condition(uint sql_errno,
}
-void THD::pop_internal_handler()
+Internal_error_handler *THD::pop_internal_handler()
{
DBUG_ASSERT(m_internal_handler != NULL);
+ Internal_error_handler *popped_handler= m_internal_handler;
m_internal_handler= m_internal_handler->m_prev_internal_handler;
+ return popped_handler;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2efff63354a..98b502c0d19 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -2584,7 +2584,7 @@ public:
/**
Remove the error handler last pushed.
*/
- void pop_internal_handler();
+ Internal_error_handler *pop_internal_handler();
/**
Raise an exception condition.
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 6da734592dc..14b5e160629 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1675,6 +1675,7 @@ void st_select_lex::init_query()
having= prep_having= where= prep_where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
+ group_fix_field= 0;
context.select_lex= this;
context.init();
/*
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7ec87806ea5..0b27f73e763 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -677,6 +677,8 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
+ /* TRUE when GROUP BY fix field called in processing of this SELECT */
+ bool group_fix_field;
/* List of references to fields referenced from inner selects */
List<Item_outer_ref> inner_refs_list;
/* Number of Item_sum-derived objects in this SELECT */
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 468f81a7d87..08fef490ad0 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -290,6 +290,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
all_fields List of all fields used in select
select Current select
ref_pointer_array Array of references to Items used in current select
+ group_list GROUP BY list (is NULL by default)
DESCRIPTION
The function serves 3 purposes - adds fields referenced from inner
@@ -308,6 +309,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
function is aggregated in the select where the outer field was
resolved or in some more inner select then the Item_direct_ref
class should be used.
+ Also it should be used if we are grouping by a subquery containing
+ the outer field.
The resolution is done here and not at the fix_fields() stage as
it can be done only after sum functions are fixed and pulled up to
selects where they are have to be aggregated.
@@ -324,7 +327,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
bool
fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
- Item **ref_pointer_array)
+ Item **ref_pointer_array, ORDER *group_list)
{
Item_outer_ref *ref;
bool res= FALSE;
@@ -374,6 +377,22 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
}
}
}
+ else
+ {
+ /*
+ Check if GROUP BY item trees contain the outer ref:
+ in this case we have to use Item_direct_ref instead of Item_ref.
+ */
+ for (ORDER *group= group_list; group; group= group->next)
+ {
+ if ((*group->item)->walk(&Item::find_item_processor, TRUE,
+ (uchar *) ref))
+ {
+ direct_ref= TRUE;
+ break;
+ }
+ }
+ }
new_ref= direct_ref ?
new Item_direct_ref(ref->context, item_ref, ref->table_name,
ref->field_name, ref->alias_name_used) :
@@ -580,7 +599,8 @@ JOIN::prepare(Item ***rref_pointer_array,
}
if (select_lex->inner_refs_list.elements &&
- fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array))
+ fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array,
+ group_list))
DBUG_RETURN(-1);
if (group_list)
@@ -2334,7 +2354,13 @@ JOIN::destroy()
tab->cleanup();
}
tmp_join->tmp_join= 0;
- tmp_table_param.copy_field= 0;
+ /*
+ We need to clean up tmp_table_param for reusable JOINs (having non-zero
+ and different from self tmp_join) because it's not being cleaned up
+ anywhere else (as we need to keep the join is reusable).
+ */
+ tmp_table_param.cleanup();
+ tmp_table_param.copy_field= tmp_join->tmp_table_param.copy_field= 0;
DBUG_RETURN(tmp_join->destroy());
}
cond_equal= 0;
@@ -5939,6 +5965,12 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table)
const_table_map= 0;
tmp_table_param.field_count= tmp_table_param.sum_func_count=
tmp_table_param.func_count= 0;
+ /*
+ We need to destruct the copy_field (allocated in create_tmp_table())
+ before setting it to 0 if the join is not "reusable".
+ */
+ if (!tmp_join || tmp_join != this)
+ tmp_table_param.cleanup();
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
first_record= sort_and_group=0;
send_records= (ha_rows) 0;
@@ -6709,10 +6741,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
case JT_CONST: // Only happens with left join
if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread)
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ table->set_keyread(TRUE);
break;
case JT_ALL:
/*
@@ -6773,10 +6802,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && //not index_merge
table->covering_keys.is_set(tab->select->quick->index))
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ table->set_keyread(TRUE);
else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick))
{ // Only read index tree
@@ -6860,11 +6886,7 @@ void JOIN_TAB::cleanup()
limit= 0;
if (table)
{
- if (table->key_read)
- {
- table->key_read= 0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE);
table->file->ha_index_or_rnd_end();
/*
We need to reset this for next select
@@ -9953,7 +9975,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
KEY_PART_INFO *key_part_info;
Item **copy_func;
MI_COLUMNDEF *recinfo;
- uint total_uneven_bit_length= 0;
+ /*
+ total_uneven_bit_length is uneven bit length for visible fields
+ hidden_uneven_bit_length is uneven bit length for hidden fields
+ */
+ uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0;
bool force_copy_fields= param->force_copy_fields;
/* Treat sum functions as normal ones when loose index scan is used. */
save_sum_fields|= param->precomputed_group_by;
@@ -10232,6 +10258,14 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*/
param->hidden_field_count= fieldnr;
null_count= 0;
+ /*
+ On last hidden field we store uneven bit length in
+ hidden_uneven_bit_length and proceed calculation of
+ uneven bits for visible fields into
+ total_uneven_bit_length variable.
+ */
+ hidden_uneven_bit_length= total_uneven_bit_length;
+ total_uneven_bit_length= 0;
}
}
DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field));
@@ -10277,7 +10311,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
else
null_count++;
}
- hidden_null_pack_length=(hidden_null_count+7)/8;
+ hidden_null_pack_length= (hidden_null_count + 7 +
+ hidden_uneven_bit_length) / 8;
null_pack_length= (hidden_null_pack_length +
(null_count + total_uneven_bit_length + 7) / 8);
reclength+=null_pack_length;
@@ -11691,21 +11726,45 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
}
SQL_SELECT *select=join_tab->select;
- if (rc == NESTED_LOOP_OK &&
- (!join_tab->cache.select || !join_tab->cache.select->skip_record()))
+ if (rc == NESTED_LOOP_OK)
{
- uint i;
- reset_cache_read(&join_tab->cache);
- for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
+ bool consider_record= !join_tab->cache.select ||
+ !join_tab->cache.select->skip_record();
+
+ /*
+ Check for error: skip_record() can execute code by calling
+ Item_subselect::val_*. We need to check for errors (if any)
+ after such call.
+ */
+ if (join->thd->is_error())
{
- read_cached_record(join_tab);
- if (!select || !select->skip_record())
+ reset_cache_write(&join_tab->cache);
+ return NESTED_LOOP_ERROR;
+ }
+
+ if (consider_record)
+ {
+ uint i;
+ reset_cache_read(&join_tab->cache);
+ for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
{
- rc= (join_tab->next_select)(join,join_tab+1,0);
- if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ read_cached_record(join_tab);
+ if (!select || !select->skip_record())
{
- reset_cache_write(&join_tab->cache);
- return rc;
+ /*
+ Check for error: skip_record() can execute code by calling
+ Item_subselect::val_*. We need to check for errors (if any)
+ after such call.
+ */
+ if (join->thd->is_error())
+ rc= NESTED_LOOP_ERROR;
+ else
+ rc= (join_tab->next_select)(join,join_tab+1,0);
+ if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ {
+ reset_cache_write(&join_tab->cache);
+ return rc;
+ }
}
}
}
@@ -11790,16 +11849,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
!table->no_keyread &&
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
{
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
+ table->set_keyread(TRUE);
tab->index= tab->ref.key;
}
error=join_read_const(tab);
- if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE);
if (error)
{
tab->info="unique row not found";
@@ -12152,12 +12206,8 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
- if (!table->key_read && table->covering_keys.is_set(tab->index) &&
- !table->no_keyread)
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ if (table->covering_keys.is_set(tab->index) && !table->no_keyread)
+ table->set_keyread(TRUE);
tab->table->status=0;
tab->read_record.read_record=join_read_next;
tab->read_record.table=table;
@@ -12191,12 +12241,8 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
- if (!table->key_read && table->covering_keys.is_set(tab->index) &&
- !table->no_keyread)
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ if (table->covering_keys.is_set(tab->index) && !table->no_keyread)
+ table->set_keyread(TRUE);
tab->table->status=0;
tab->read_record.read_record=join_read_prev;
tab->read_record.table=table;
@@ -12963,7 +13009,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
key_part_end=key_part+table->key_info[idx].key_parts;
key_part_map const_key_parts=table->const_key_parts[idx];
int reverse=0;
- my_bool on_primary_key= FALSE;
+ my_bool on_pk_suffix= FALSE;
DBUG_ENTER("test_if_order_by_key");
for (; order ; order=order->next, const_key_parts>>=1)
@@ -12985,11 +13031,12 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
key as a suffix to the secondary keys. If it has continue to check
the primary key as a suffix.
*/
- if (!on_primary_key &&
+ if (!on_pk_suffix &&
(table->file->ha_table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) &&
- table->s->primary_key != MAX_KEY)
+ table->s->primary_key != MAX_KEY &&
+ table->s->primary_key != idx)
{
- on_primary_key= TRUE;
+ on_pk_suffix= TRUE;
key_part= table->key_info[table->s->primary_key].key_part;
key_part_end=key_part+table->key_info[table->s->primary_key].key_parts;
const_key_parts=table->const_key_parts[table->s->primary_key];
@@ -13021,7 +13068,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
reverse=flag; // Remember if reverse
key_part++;
}
- if (on_primary_key)
+ if (on_pk_suffix)
{
uint used_key_parts_secondary= table->key_info[idx].key_parts;
uint used_key_parts_pk=
@@ -13510,8 +13557,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select_limit= table_records;
if (group)
{
- rec_per_key= used_key_parts ? keyinfo->rec_per_key[used_key_parts-1]
- : 1;
+ /*
+ Used_key_parts can be larger than keyinfo->key_parts
+ when using a secondary index clustered with a primary
+ key (e.g. as in Innodb).
+ See Bug #28591 for details.
+ */
+ rec_per_key= used_key_parts &&
+ used_key_parts <= keyinfo->key_parts ?
+ keyinfo->rec_per_key[used_key_parts-1] : 1;
set_if_bigger(rec_per_key, 1);
/*
With a grouping query each group containing on average
@@ -13612,11 +13666,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If ref_key used index tree reading only ('Using index' in EXPLAIN),
and best_key doesn't, then revert the decision.
*/
- if (!table->covering_keys.is_set(best_key) && table->key_read)
- {
- table->key_read= 0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ if (!table->covering_keys.is_set(best_key))
+ table->set_keyread(FALSE);
if (!quick_created)
{
tab->index= best_key;
@@ -13629,10 +13680,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->quick= 0;
}
if (table->covering_keys.is_set(best_key))
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
+ table->set_keyread(TRUE);
table->file->ha_index_or_rnd_end();
if (join->select_options & SELECT_DESCRIBE)
{
@@ -13806,11 +13854,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
We can only use 'Only index' if quick key is same as ref_key
and in index_merge 'Only index' cannot be used
*/
- if (table->key_read && ((uint) tab->ref.key != select->quick->index))
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ if (((uint) tab->ref.key != select->quick->index))
+ table->set_keyread(FALSE);
}
else
{
@@ -13866,11 +13911,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_read_record;
tab->join->examined_rows+=examined_rows;
- if (table->key_read) // Restore if we used indexes
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE); // Restore if we used indexes
DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err:
DBUG_RETURN(-1);
@@ -14307,7 +14348,7 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
used_fields--;
length+=field->fill_cache_field(copy);
- if (copy->blob_field)
+ if (copy->type == CACHE_BLOB)
(*blob_ptr++)=copy;
if (field->real_maybe_null())
null_fields++;
@@ -14322,8 +14363,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{ /* must copy null bits */
copy->str= tables[i].table->null_flags;
copy->length= tables[i].table->s->null_bytes;
- copy->strip=0;
- copy->blob_field=0;
+ copy->type=0;
+ copy->field=0;
length+=copy->length;
copy++;
cache->fields++;
@@ -14333,8 +14374,8 @@ join_init_cache(THD *thd,JOIN_TAB *tables,uint table_count)
{
copy->str= (uchar*) &tables[i].table->null_row;
copy->length=sizeof(tables[i].table->null_row);
- copy->strip=0;
- copy->blob_field=0;
+ copy->type=0;
+ copy->field=0;
length+=copy->length;
copy++;
cache->fields++;
@@ -14359,9 +14400,10 @@ used_blob_length(CACHE_FIELD **ptr)
uint length,blob_length;
for (length=0 ; *ptr ; ptr++)
{
- (*ptr)->blob_length=blob_length=(*ptr)->blob_field->get_length();
+ Field_blob *field_blob= (Field_blob *) (*ptr)->field;
+ (*ptr)->blob_length=blob_length= field_blob->get_length();
length+=blob_length;
- (*ptr)->blob_field->get_ptr(&(*ptr)->str);
+ field_blob->get_ptr(&(*ptr)->str);
}
return length;
}
@@ -14390,30 +14432,35 @@ store_record_in_cache(JOIN_CACHE *cache)
cache->records++;
for (copy=cache->field ; copy < end_field; copy++)
{
- if (copy->blob_field)
+ if (copy->type == CACHE_BLOB)
{
+ Field_blob *blob_field= (Field_blob *) copy->field;
if (last_record)
{
- copy->blob_field->get_image(pos, copy->length+sizeof(char*),
- copy->blob_field->charset());
+ blob_field->get_image(pos, copy->length+sizeof(char*),
+ blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
- copy->blob_field->get_image(pos, copy->length, // blob length
- copy->blob_field->charset());
+ blob_field->get_image(pos, copy->length, // blob length
+ blob_field->charset());
memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
pos+=copy->length+copy->blob_length;
}
}
else
{
- if (copy->strip)
+ if (copy->type == CACHE_STRIPPED)
{
uchar *str,*end;
- for (str=copy->str,end= str+copy->length;
- end > str && end[-1] == ' ' ;
- end--) ;
+ Field *field= copy->field;
+ if (field && field->maybe_null() && field->is_null())
+ end= str= copy->str;
+ else
+ for (str=copy->str,end= str+copy->length;
+ end > str && end[-1] == ' ' ;
+ end--) ;
length=(uint) (end-str);
memcpy(pos+2, str, length);
int2store(pos, length);
@@ -14462,23 +14509,24 @@ read_cached_record(JOIN_TAB *tab)
copy < end_field;
copy++)
{
- if (copy->blob_field)
+ if (copy->type == CACHE_BLOB)
{
+ Field_blob *blob_field= (Field_blob *) copy->field;
if (last_record)
{
- copy->blob_field->set_image(pos, copy->length+sizeof(char*),
- copy->blob_field->charset());
+ blob_field->set_image(pos, copy->length+sizeof(char*),
+ blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
- copy->blob_field->set_ptr(pos, pos+copy->length);
- pos+=copy->length+copy->blob_field->get_length();
+ blob_field->set_ptr(pos, pos+copy->length);
+ pos+=copy->length + blob_field->get_length();
}
}
else
{
- if (copy->strip)
+ if (copy->type == CACHE_STRIPPED)
{
length= uint2korr(pos);
memcpy(copy->str, pos+2, length);
@@ -14689,11 +14737,29 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
We check order_item->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called.
+
+ group_fix_field= TRUE is to resolve aliases from the SELECT list
+ without creating of Item_ref-s: JOIN::exec() wraps aliased items
+ in SELECT list with Item_copy items. To re-evaluate such a tree
+ that includes Item_copy items we have to refresh Item_copy caches,
+ but:
+ - filesort() never refresh Item_copy items,
+ - end_send_group() checks every record for group boundary by the
+ test_if_group_changed function that obtain data from these
+ Item_copy items, but the copy_fields function that
+ refreshes Item copy items is called after group boundaries only -
+ that is a vicious circle.
+ So we prevent inclusion of Item_copy items.
*/
- if (!order_item->fixed &&
+ bool save_group_fix_field= thd->lex->current_select->group_fix_field;
+ if (is_group_field)
+ thd->lex->current_select->group_fix_field= TRUE;
+ bool ret= (!order_item->fixed &&
(order_item->fix_fields(thd, order->item) ||
(order_item= *order->item)->check_cols(1) ||
- thd->is_fatal_error))
+ thd->is_fatal_error));
+ thd->lex->current_select->group_fix_field= save_group_fix_field;
+ if (ret)
return TRUE; /* Wrong field. */
uint el= all_fields.elements;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c30aae4fbf9..3cec00a84c8 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -98,6 +98,10 @@ typedef struct st_table_ref
} TABLE_REF;
+
+#define CACHE_BLOB 1 /* blob field */
+#define CACHE_STRIPPED 2 /* field stripped of trailing spaces */
+
/**
CACHE_FIELD and JOIN_CACHE is used on full join to cache records in outer
table
@@ -106,8 +110,8 @@ typedef struct st_table_ref
typedef struct st_cache_field {
uchar *str;
uint length, blob_length;
- Field_blob *blob_field;
- bool strip;
+ Field *field;
+ uint type; /**< category of the of the copied field (CACHE_BLOB et al.) */
} CACHE_FIELD;
@@ -361,7 +365,25 @@ public:
*/
bool no_const_tables;
- JOIN *tmp_join; ///< copy of this JOIN to be used with temporary tables
+ /**
+ Copy of this JOIN to be used with temporary tables.
+
+ tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery
+ that gets re-executed several times) and we know will use temporary tables
+ for materialization. The materialization to a temporary table overwrites the
+ JOIN structure to point to the temporary table after the materialization is
+ done. This is where tmp_join is used : it's a copy of the JOIN before the
+ materialization and is used in restoring before re-execution by overwriting
+ the current JOIN structure with the saved copy.
+ Because of this we should pay extra care of not freeing up helper structures
+ that are referenced by the original contents of the JOIN. We can check for
+ this by making sure the "current" join is not the temporary copy, e.g.
+ !tmp_join || tmp_join != join
+
+ We should free these sub-structures at JOIN::destroy() if the "current" join
+ has a copy is not that copy.
+ */
+ JOIN *tmp_join;
ROLLUP rollup; ///< Used with rollup
bool select_distinct; ///< Set if SELECT DISTINCT
@@ -724,10 +746,11 @@ public:
we need to check for errors executing it and react accordingly
*/
if (!res && table->in_use->is_error())
- res= 2;
+ res= 1; /* STORE_KEY_FATAL */
dbug_tmp_restore_column_map(table->write_set, old_map);
null_key= to_field->is_null() || item->null_value;
- return (err != 0 || res > 2 ? STORE_KEY_FATAL : (store_key_result) res);
+ return ((err != 0 || res < 0 || res > 2) ? STORE_KEY_FATAL :
+ (store_key_result) res);
}
};
@@ -756,17 +779,17 @@ protected:
if ((res= item->save_in_field(to_field, 1)))
{
if (!err)
- err= res;
+ err= res < 0 ? 1 : res; /* 1=STORE_KEY_FATAL */
}
/*
Item::save_in_field() may call Item::val_xxx(). And if this is a subquery
we need to check for errors executing it and react accordingly
*/
if (!err && to_field->table->in_use->is_error())
- err= 2;
+ err= 1; /* STORE_KEY_FATAL */
}
null_key= to_field->is_null() || item->null_value;
- return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
+ return (err > 2 ? STORE_KEY_FATAL : (store_key_result) err);
}
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9acbc37fd9a..940adcd3ce6 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1896,22 +1896,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
mysql_ha_rm_tables(thd, tables);
- /*
- If we have the table in the definition cache, we don't have to check the
- .frm file to find if the table is a normal table (not view) and what
- engine to use.
- */
+ /* Disable drop of enabled log tables, must be done before name locking */
mysql_mutex_lock(&LOCK_open);
for (table= tables; table; table= table->next_local)
{
- TABLE_SHARE *share;
- table->db_type= NULL;
- if ((share= get_cached_table_share(table->db, table->table_name)))
- table->db_type= share->db_type();
-
- /* Disable drop of enabled log tables */
- if (share && (share->table_category == TABLE_CATEGORY_LOG) &&
- check_if_log_table(table->db_length, table->db,
+ if (check_if_log_table(table->db_length, table->db,
table->table_name_length, table->table_name, 1))
{
mysql_mutex_unlock(&LOCK_open);
@@ -1974,7 +1963,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
char *db=table->db;
handlerton *table_type;
- enum legacy_db_type frm_db_type;
+ enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
DBUG_PRINT("table", ("table_l: '%s'.'%s' table: 0x%lx s: 0x%lx",
table->db, table->table_name, (long) table->table,
@@ -2042,7 +2031,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
built_query.append("`,");
}
- table_type= table->db_type;
if (!drop_temporary)
{
if (thd->locked_tables_mode)
@@ -2072,10 +2060,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
TODO: Investigate what should be done to remove this lock completely.
Is exclusive meta-data lock enough ?
*/
+ DEBUG_SYNC(thd, "rm_table_part2_before_delete_table");
mysql_mutex_lock(&LOCK_open);
if (drop_temporary ||
- ((table_type == NULL &&
- access(path, F_OK) &&
+ ((access(path, F_OK) &&
ha_create_table_from_engine(thd, db, alias)) ||
(!drop_view &&
mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
@@ -2091,15 +2079,25 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
else
{
char *end;
- if (table_type == NULL)
+ /*
+ Cannot use the db_type from the table, since that might have changed
+ while waiting for the exclusive name lock. We are under LOCK_open,
+ so reading from the frm-file is safe.
+ */
+ if (frm_db_type == DB_TYPE_UNKNOWN)
{
- mysql_frm_type(thd, path, &frm_db_type);
- table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
+ mysql_frm_type(thd, path, &frm_db_type);
+ DBUG_PRINT("info", ("frm_db_type %d from %s", frm_db_type, path));
}
+ table_type= ha_resolve_by_legacy_type(thd, frm_db_type);
// Remove extension for delete
*(end= path + path_length - reg_ext_length)= '\0';
+ DBUG_PRINT("info", ("deleting table of type %d",
+ (table_type ? table_type->db_type : 0)));
error= ha_delete_table(thd, table_type, path, db, table->table_name,
!dont_log_query);
+
+ /* No error if non existent table and 'IF EXIST' clause or view */
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) &&
(if_exists || table_type == NULL))
{
@@ -2141,6 +2139,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
table->table_name););
}
+ DEBUG_SYNC(thd, "rm_table_part2_before_binlog");
thd->thread_specific_used|= tmp_table_deleted;
error= 0;
if (wrong_tables.length())
@@ -7128,6 +7127,7 @@ view_err:
else
create_info->data_file_name=create_info->index_file_name=0;
+ DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock");
/*
Create a table with a temporary name.
With create_info->frm_only == 1 this creates a .frm file only.
@@ -7337,6 +7337,7 @@ view_err:
close_temporary_table(thd, new_table, 1, 0);
new_table= 0;
}
+ DEBUG_SYNC(thd, "alter_table_before_rename_result_table");
/*
Data is copied. Now we:
@@ -7479,6 +7480,7 @@ view_err:
thd_proc_info(thd, "end");
DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000););
+ DEBUG_SYNC(thd, "alter_table_before_main_binlog");
ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE,
thd->query(), thd->query_length(),
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index c2ab740f29b..b1367a61b37 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -330,6 +330,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
String stmt_query;
bool lock_upgrade_done= FALSE;
MDL_ticket *mdl_ticket= NULL;
+ Query_tables_list backup;
DBUG_ENTER("mysql_create_or_drop_trigger");
@@ -393,6 +394,12 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
{
bool if_exists= thd->lex->drop_if_exists;
+ /*
+ Protect the query table list from the temporary and potentially
+ destructive changes necessary to open the trigger's table.
+ */
+ thd->lex->reset_n_backup_query_tables_list(&backup);
+
if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
goto end;
@@ -522,6 +529,10 @@ end:
if (thd->locked_tables_mode && tables && lock_upgrade_done)
mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+ /* Restore the query table list. Used only for drop trigger. */
+ if (!create)
+ thd->lex->restore_backup_query_tables_list(&backup);
+
if (thd->global_read_lock.has_protection())
thd->global_read_lock.start_waiting_global_read_lock(thd);
@@ -1636,10 +1647,6 @@ bool add_table_for_trigger(THD *thd,
if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name))
DBUG_RETURN(TRUE);
- /* We need to reset statement table list to be PS/SP friendly. */
- lex->query_tables= 0;
- lex->query_tables_last= &lex->query_tables;
-
*table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str,
tbl_name.str, TL_IGNORE);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index a163dda2c69..1643bce8ddd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -400,10 +400,7 @@ int mysql_update(THD *thd,
matching rows before updating the table!
*/
if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
- {
- table->key_read=1;
table->mark_columns_used_by_index(used_index);
- }
else
{
table->use_all_columns();
@@ -852,11 +849,7 @@ int mysql_update(THD *thd,
err:
delete select;
free_underlaid_joins(thd, select_lex);
- if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
+ table->set_keyread(FALSE);
thd->abort_on_warning= 0;
DBUG_RETURN(1);
}
@@ -1192,6 +1185,57 @@ reopen_tables:
}
+/**
+ Implementation of the safe update options during UPDATE IGNORE. This syntax
+ causes an UPDATE statement to ignore all errors. In safe update mode,
+ however, we must never ignore the ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE. There
+ is a special hook in my_message_sql that will otherwise delete all errors
+ when the IGNORE option is specified.
+
+ In the future, all IGNORE handling should be used with this class and all
+ traces of the hack outlined below should be removed.
+
+ - The parser detects IGNORE option and sets thd->lex->ignore= 1
+
+ - In JOIN::optimize, if this is set, then
+ thd->lex->current_select->no_error gets set.
+
+ - In my_message_sql(), if the flag above is set then any error is
+ unconditionally converted to a warning.
+
+ We are moving in the direction of using Internal_error_handler subclasses
+ to do all such error tweaking, please continue this effort if new bugs
+ appear.
+ */
+class Safe_dml_handler : public Internal_error_handler {
+
+private:
+ bool m_handled_error;
+
+public:
+ explicit Safe_dml_handler() : m_handled_error(FALSE) {}
+
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+ {
+ if (level == MYSQL_ERROR::WARN_LEVEL_ERROR &&
+ sql_errno == ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE)
+ {
+ thd->stmt_da->set_error_status(thd, sql_errno, msg, sqlstate);
+ m_handled_error= TRUE;
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ bool handled_error() { return m_handled_error; }
+
+};
+
/*
Setup multi-update handling and call SELECT to do the join
*/
@@ -1224,18 +1268,36 @@ bool mysql_multi_update(THD *thd,
MODE_STRICT_ALL_TABLES));
List<Item> total_list;
+
+ Safe_dml_handler handler;
+ bool using_handler= thd->variables.option_bits & OPTION_SAFE_UPDATES;
+ if (using_handler)
+ thd->push_internal_handler(&handler);
+
res= mysql_select(thd, &select_lex->ref_pointer_array,
- table_list, select_lex->with_wild,
- total_list,
- conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
- (ORDER *)NULL,
- options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
- OPTION_SETUP_TABLES_DONE,
- *result, unit, select_lex);
- DBUG_PRINT("info",("res: %d report_error: %d", res,
- (int) thd->is_error()));
+ table_list, select_lex->with_wild,
+ total_list,
+ conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
+ (ORDER *)NULL,
+ options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
+ OPTION_SETUP_TABLES_DONE,
+ *result, unit, select_lex);
+
+ if (using_handler)
+ {
+ Internal_error_handler *top_handler;
+ top_handler= thd->pop_internal_handler();
+ DBUG_ASSERT(&handler == top_handler);
+ }
+
+ DBUG_PRINT("info",("res: %d report_error: %d", res, (int) thd->is_error()));
res|= thd->is_error();
- if (unlikely(res))
+ /*
+ Todo: remove below code and make Safe_dml_handler do error processing
+ instead. That way we can return the actual error instead of
+ ER_UNKNOWN_ERROR.
+ */
+ if (unlikely(res) && (!using_handler || !handler.handled_error()))
{
/* If we had a another error reported earlier then this will be ignored */
(*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index b9eb6a63552..60971f51154 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -405,17 +405,14 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
view= lex->unlink_first_table(&link_to_local);
- if (mode != VIEW_CREATE_NEW)
+ if (mode == VIEW_ALTER && fill_defined_view_parts(thd, view))
{
- if (mode == VIEW_ALTER &&
- fill_defined_view_parts(thd, view))
- {
- res= TRUE;
- goto err;
- }
- sp_cache_invalidate();
+ res= TRUE;
+ goto err;
}
+ sp_cache_invalidate();
+
if (!lex->definer)
{
/*
diff --git a/sql/table.cc b/sql/table.cc
index 0e66ff9da94..fa1186c2a45 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -3410,7 +3410,7 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
void TABLE_LIST::hide_view_error(THD *thd)
{
- if (thd->get_internal_handler())
+ if (thd->killed || thd->get_internal_handler())
return;
/* Hide "Unknown column" or "Unknown function" error */
DBUG_ASSERT(thd->is_error());
@@ -4421,7 +4421,7 @@ void TABLE::mark_columns_used_by_index(uint index)
MY_BITMAP *bitmap= &tmp_set;
DBUG_ENTER("TABLE::mark_columns_used_by_index");
- (void) file->extra(HA_EXTRA_KEYREAD);
+ set_keyread(TRUE);
bitmap_clear_all(bitmap);
mark_columns_used_by_index_no_reset(index, bitmap);
column_bitmaps_set(bitmap, bitmap);
@@ -4444,8 +4444,7 @@ void TABLE::restore_column_maps_after_mark_index()
{
DBUG_ENTER("TABLE::restore_column_maps_after_mark_index");
- key_read= 0;
- (void) file->extra(HA_EXTRA_NO_KEYREAD);
+ set_keyread(FALSE);
default_column_bitmaps();
file->column_bitmaps_signal();
DBUG_VOID_RETURN;
diff --git a/sql/table.h b/sql/table.h
index 3d11118a3ea..3832e7c9555 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -950,6 +950,21 @@ public:
*/
inline bool needs_reopen()
{ return !db_stat || m_needs_reopen; }
+
+ inline void set_keyread(bool flag)
+ {
+ DBUG_ASSERT(file);
+ if (flag && !key_read)
+ {
+ key_read= 1;
+ file->extra(HA_EXTRA_KEYREAD);
+ }
+ else if (!flag && key_read)
+ {
+ key_read= 0;
+ file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ }
};