summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/filesort.cc7
-rw-r--r--sql/ha_ndbcluster_cond.cc2
-rw-r--r--sql/handler.cc1
-rw-r--r--sql/item_cmpfunc.cc49
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_strfunc.cc64
-rw-r--r--sql/item_strfunc.h5
-rw-r--r--sql/item_timefunc.cc13
-rw-r--r--sql/item_timefunc.h9
-rw-r--r--sql/mysqld.cc32
-rw-r--r--sql/repl_failsafe.cc366
-rw-r--r--sql/repl_failsafe.h7
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/share/errmsg-utf8.txt3
-rw-r--r--sql/sp_head.cc1
-rw-r--r--sql/sql_acl.cc8
-rw-r--r--sql/sql_connect.cc31
-rw-r--r--sql/sql_connect.h2
-rw-r--r--sql/sql_lex.h5
-rw-r--r--sql/sql_parse.cc14
-rw-r--r--sql/sql_parse.h6
-rw-r--r--sql/sql_repl.cc17
-rw-r--r--sql/sql_repl.h2
-rw-r--r--sql/sql_select.cc66
-rw-r--r--sql/sql_string.cc4
-rw-r--r--sql/sql_string.h3
-rw-r--r--sql/sql_update.cc98
-rw-r--r--sql/sql_yacc.yy13
-rw-r--r--sql/sys_vars.cc2
-rw-r--r--sql/transaction.cc5
30 files changed, 333 insertions, 506 deletions
diff --git a/sql/filesort.cc b/sql/filesort.cc
index cf5334cd87f..c3250b6e699 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -32,6 +32,7 @@
#include "probes_mysql.h"
#include "sql_test.h" // TEST_filesort
#include "opt_range.h" // SQL_SELECT
+#include "debug_sync.h"
/// How to write record_ref.
#define WRITE_REF(file,from) \
@@ -123,6 +124,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
MYSQL_FILESORT_START(table->s->db.str, table->s->table_name.str);
+ DEBUG_SYNC(thd, "filesort_start");
/*
Release InnoDB's adaptive hash index latch (if holding) before
@@ -325,12 +327,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
}
if (error)
{
- DBUG_ASSERT(thd->is_error());
+ int kill_errno= thd->killed_errno();
+ DBUG_ASSERT(thd->is_error() || kill_errno);
my_printf_error(ER_FILSORT_ABORT,
"%s: %s",
MYF(ME_ERROR + ME_WAITTANG),
ER_THD(thd, ER_FILSORT_ABORT),
- thd->stmt_da->message());
+ kill_errno ? ER(kill_errno) : thd->stmt_da->message());
if (global_system_variables.log_warnings > 1)
{
diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc
index 8a96ae41453..9ab7fb6208d 100644
--- a/sql/ha_ndbcluster_cond.cc
+++ b/sql/ha_ndbcluster_cond.cc
@@ -1472,4 +1472,4 @@ int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op,
DBUG_RETURN(0);
}
-#endif /* HAVE_NDBCLUSTER_DB */
+#endif
diff --git a/sql/handler.cc b/sql/handler.cc
index f7690c28827..9ca1f3a20f8 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2700,6 +2700,7 @@ void handler::print_error(int error, myf errflag)
break;
case HA_ERR_KEY_NOT_FOUND:
case HA_ERR_NO_ACTIVE_RECORD:
+ case HA_ERR_RECORD_DELETED:
case HA_ERR_END_OF_FILE:
textno=ER_KEY_NOT_FOUND;
break;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 67635c73b43..68c63285693 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2640,7 +2640,7 @@ Item_func_if::fix_length_and_dec()
if (null1)
{
cached_result_type= arg2_type;
- collation.set(args[2]->collation.collation);
+ collation.set(args[2]->collation);
cached_field_type= args[2]->field_type();
max_length= args[2]->max_length;
return;
@@ -2649,7 +2649,7 @@ Item_func_if::fix_length_and_dec()
if (null2)
{
cached_result_type= arg1_type;
- collation.set(args[1]->collation.collation);
+ collation.set(args[1]->collation);
cached_field_type= args[1]->field_type();
max_length= args[1]->max_length;
return;
@@ -3054,20 +3054,59 @@ void Item_func_case::fix_length_and_dec()
agg[0]= args[first_expr_num];
left_result_type= agg[0]->result_type();
+ /*
+ As the first expression and WHEN expressions
+ are intermixed in args[] array THEN and ELSE items,
+ extract the first expression and all WHEN expressions into
+ a temporary array, to process them easier.
+ */
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
if (!(found_types= collect_cmp_types(agg, nagg)))
return;
+ if (found_types & (1 << STRING_RESULT))
+ {
+ /*
+ If we'll do string comparison, we also need to aggregate
+ character set and collation for first/WHEN items and
+ install converters for some of them to cmp_collation when necessary.
+ This is done because cmp_item compatators cannot compare
+ strings in two different character sets.
+ Some examples when we install converters:
+
+ 1. Converter installed for the first expression:
+
+ CASE latin1_item WHEN utf16_item THEN ... END
+
+ is replaced to:
+
+ CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END
+
+ 2. Converter installed for the left WHEN item:
+ CASE utf16_item WHEN latin1_item THEN ... END
+
+ is replaced to:
+
+ CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
+ */
+ if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
+ return;
+ /*
+ Now copy first expression and all WHEN expressions back to args[]
+ arrray, because some of the items might have been changed to converters
+ (e.g. Item_func_conv_charset, or Item_string for constants).
+ */
+ args[first_expr_num]= agg[0];
+ for (nagg= 0; nagg < ncases / 2; nagg++)
+ args[nagg * 2]= agg[nagg + 1];
+ }
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
- return;
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
cmp_collation.collation)))
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e28d8b8bcc4..9195cf4f8c7 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -868,7 +868,7 @@ longlong Item_func_numhybrid::val_int()
return 0;
char *end= (char*) res->ptr() + res->length();
- CHARSET_INFO *cs= str_value.charset();
+ CHARSET_INFO *cs= res->charset();
return (*(cs->cset->strtoll10))(cs, res->ptr(), &end, &err_not_used);
}
default:
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 0248c133f60..ad18d5dabbe 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -699,6 +699,7 @@ String *Item_func_des_encrypt::val_str(String *str)
tmp_arg[res_length-1]=tail; // save extra length
tmp_value.realloc(res_length+1);
tmp_value.length(res_length+1);
+ tmp_value.set_charset(&my_charset_bin);
tmp_value[0]=(char) (128 | key_number);
// Real encryption
bzero((char*) &ivec,sizeof(ivec));
@@ -786,6 +787,7 @@ String *Item_func_des_decrypt::val_str(String *str)
if ((tail=(uint) (uchar) tmp_value[length-2]) > 8)
goto wrong_key; // Wrong key
tmp_value.length(length-1-tail);
+ tmp_value.set_charset(&my_charset_bin);
return &tmp_value;
error:
@@ -3448,14 +3450,68 @@ String *Item_func_quote::val_str(String *str)
}
arg_length= arg->length();
- new_length= arg_length+2; /* for beginning and ending ' signs */
- for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++)
- new_length+= get_esc_bit(escmask, (uchar) *from);
+ if (collation.collation->mbmaxlen == 1)
+ {
+ new_length= arg_length + 2; /* for beginning and ending ' signs */
+ for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++)
+ new_length+= get_esc_bit(escmask, (uchar) *from);
+ }
+ else
+ {
+ new_length= (arg_length * 2) + /* For string characters */
+ (2 * collation.collation->mbmaxlen); /* For quotes */
+ }
if (tmp_value.alloc(new_length))
goto null;
+ if (collation.collation->mbmaxlen > 1)
+ {
+ CHARSET_INFO *cs= collation.collation;
+ int mblen;
+ uchar *to_end;
+ to= (char*) tmp_value.ptr();
+ to_end= (uchar*) to + new_length;
+
+ /* Put leading quote */
+ if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
+ goto null;
+ to+= mblen;
+
+ for (start= (char*) arg->ptr(), end= start + arg_length; start < end; )
+ {
+ my_wc_t wc;
+ bool escape;
+ if ((mblen= cs->cset->mb_wc(cs, &wc, (uchar*) start, (uchar*) end)) <= 0)
+ goto null;
+ start+= mblen;
+ switch (wc) {
+ case 0: escape= 1; wc= '0'; break;
+ case '\032': escape= 1; wc= 'Z'; break;
+ case '\'': escape= 1; break;
+ case '\\': escape= 1; break;
+ default: escape= 0; break;
+ }
+ if (escape)
+ {
+ if ((mblen= cs->cset->wc_mb(cs, '\\', (uchar*) to, to_end)) <= 0)
+ goto null;
+ to+= mblen;
+ }
+ if ((mblen= cs->cset->wc_mb(cs, wc, (uchar*) to, to_end)) <= 0)
+ goto null;
+ to+= mblen;
+ }
+
+ /* Put trailing quote */
+ if ((mblen= cs->cset->wc_mb(cs, '\'', (uchar *) to, to_end)) <= 0)
+ goto null;
+ to+= mblen;
+ new_length= to - tmp_value.ptr();
+ goto ret;
+ }
+
/*
We replace characters from the end to the beginning
*/
@@ -3487,6 +3543,8 @@ String *Item_func_quote::val_str(String *str)
}
}
*to= '\'';
+
+ret:
tmp_value.length(new_length);
tmp_value.set_charset(collation.collation);
null_value= 0;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index fef4f9f975d..00a0b35ef58 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -787,9 +787,10 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 + 2;
- max_length= (uint32) min(max_result_length, MAX_BLOB_WIDTH);
collation.set(args[0]->collation);
+ ulonglong max_result_length= (ulonglong) args[0]->max_length * 2 +
+ 2 * collation.collation->mbmaxlen;
+ max_length= (uint32) min(max_result_length, MAX_BLOB_WIDTH);
}
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 3d587ace335..99467b7c3fc 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1133,16 +1133,13 @@ String* Item_func_monthname::val_str(String* str)
{
DBUG_ASSERT(fixed == 1);
const char *month_name;
- uint month= (uint) val_int();
uint err;
+ MYSQL_TIME ltime;
- if (null_value || !month)
- {
- null_value=1;
- return (String*) 0;
- }
- null_value=0;
- month_name= locale->month_names->type_names[month-1];
+ if ((null_value= (get_arg0_date(&ltime, TIME_FUZZY_DATE) || !ltime.month)))
+ return (String *) 0;
+
+ month_name= locale->month_names->type_names[ltime.month - 1];
str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
collation.collation, &err);
return str;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 9732e8dc360..92e24d75111 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -163,16 +163,19 @@ public:
};
-class Item_func_monthname :public Item_func_month
+class Item_func_monthname :public Item_str_func
{
MY_LOCALE *locale;
public:
- Item_func_monthname(Item *a) :Item_func_month(a) {}
+ Item_func_monthname(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "monthname"; }
String *val_str(String *str);
- enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
+ bool check_valid_arguments_processor(uchar *int_arg)
+ {
+ return !has_date_args();
+ }
};
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 8f5fed07948..3c06832e9a6 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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
@@ -1274,11 +1274,14 @@ static void __cdecl kill_server(int sig_ptr)
/*
Send event to smem_event_connect_request for aborting
*/
- if (!SetEvent(smem_event_connect_request))
- {
- DBUG_PRINT("error",
- ("Got error: %ld from SetEvent of smem_event_connect_request",
- GetLastError()));
+ if (opt_enable_shared_memory)
+ {
+ if (!SetEvent(smem_event_connect_request))
+ {
+ DBUG_PRINT("error",
+ ("Got error: %ld from SetEvent of smem_event_connect_request",
+ GetLastError()));
+ }
}
#endif
@@ -3029,7 +3032,6 @@ SHOW_VAR com_status_vars[]= {
{"show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS},
{"show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
{"show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
- {"show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
{"show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS},
{"show_plugins", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PLUGINS]), SHOW_LONG_STATUS},
{"show_privileges", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PRIVILEGES]), SHOW_LONG_STATUS},
@@ -4218,11 +4220,14 @@ int mysqld_main(int argc, char **argv)
to be able to read defaults files and parse options.
*/
my_progname= argv[0];
- if (my_basic_init())
+#ifndef _WIN32
+ // For windows, my_init() is called from the win specific mysqld_main
+ if (my_init()) // init my_sys library & pthreads
{
- fprintf(stderr, "my_basic_init() failed.");
+ fprintf(stderr, "my_init() failed.");
return 1;
}
+#endif
orig_argc= argc;
orig_argv= argv;
@@ -4321,11 +4326,10 @@ int mysqld_main(int argc, char **argv)
recreate objects which were initialised early,
so that they are instrumented as well.
*/
- my_thread_basic_global_reinit();
+ my_thread_global_reinit();
}
#endif /* HAVE_PSI_INTERFACE */
- my_init(); // init my_sys library & pthreads
init_error_log_mutex();
/* Set signal used to kill MySQL */
@@ -4746,6 +4750,12 @@ int mysqld_main(int argc, char **argv)
/* Must be initialized early for comparison of service name */
system_charset_info= &my_charset_utf8_general_ci;
+ if (my_init())
+ {
+ fprintf(stderr, "my_init() failed.");
+ return 1;
+ }
+
if (Service.GetOS()) /* true NT family */
{
char file_path[FN_REFLEN];
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 540b62b9d3b..bc710616a4c 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -56,10 +56,6 @@ const char* rpl_status_type[]=
"RECOVERY_CAPTAIN","NULL",NullS
};
-static Slave_log_event* find_slave_event(IO_CACHE* log,
- const char* log_file_name,
- char* errmsg);
-
/*
All of the functions defined in this file which are not used (the ones to
handle failsafe) are not used; their code has not been updated for more than
@@ -91,13 +87,6 @@ void change_rpl_status(ulong from_status, ulong to_status)
}\
-static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
-{
- return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name,
- mi->pos);
-}
-
-
void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
{
if (thd->server_id)
@@ -228,361 +217,6 @@ void end_slave_list()
}
}
-static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
-{
- my_off_t log_pos = (my_off_t) mi->pos;
- uint32 target_server_id = mi->server_id;
-
- for (;;)
- {
- Log_event* ev;
- if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*) 0, 0)))
- {
- if (log->error > 0)
- strmov(errmsg, "Binary log truncated in the middle of event");
- else if (log->error < 0)
- strmov(errmsg, "I/O error reading binary log");
- else
- strmov(errmsg, "Could not find target event in the binary log");
- return 1;
- }
-
- if (ev->log_pos >= log_pos && ev->server_id == target_server_id)
- {
- delete ev;
- mi->pos = my_b_tell(log);
- return 0;
- }
- delete ev;
- }
- /* Impossible */
-}
-
-/**
- @details
- Before 4.0.15 we had a member of THD called log_pos, it was meant for
- failsafe replication code in repl_failsafe.cc which is disabled until
- it is reworked. Event's log_pos used to be preserved through
- log-slave-updates to make code in repl_failsafe.cc work (this
- function, SHOW NEW MASTER); but on the other side it caused unexpected
- values in Exec_Master_Log_Pos in A->B->C replication setup,
- synchronization problems in master_pos_wait(), ... So we
- (Dmitri & Guilhem) removed it.
-
- So for now this function is broken.
-*/
-
-int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
-{
- LOG_INFO linfo;
- char last_log_name[FN_REFLEN];
- IO_CACHE log;
- File file = -1, last_file = -1;
- mysql_mutex_t *log_lock;
- const char* errmsg_p;
- Slave_log_event* sev = 0;
- my_off_t last_pos = 0;
- int error = 1;
- int cmp_res;
- LINT_INIT(cmp_res);
- DBUG_ENTER("translate_master");
-
- if (!mysql_bin_log.is_open())
- {
- strmov(errmsg,"Binary log is not open");
- DBUG_RETURN(1);
- }
-
- if (!server_id_supplied)
- {
- strmov(errmsg, "Misconfigured master - server id was not set");
- DBUG_RETURN(1);
- }
-
- if (mysql_bin_log.find_log_pos(&linfo, NullS, 1))
- {
- strmov(errmsg,"Could not find first log");
- DBUG_RETURN(1);
- }
- thd->current_linfo = &linfo;
-
- bzero((char*) &log,sizeof(log));
- log_lock = mysql_bin_log.get_log_lock();
- mysql_mutex_lock(log_lock);
-
- for (;;)
- {
- if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
- {
- strmov(errmsg, errmsg_p);
- goto err;
- }
-
- if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
- goto err;
-
- cmp_res = cmp_master_pos(sev, mi);
- delete sev;
-
- if (!cmp_res)
- {
- /* Copy basename */
- fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
- mi->pos = my_b_tell(&log);
- goto mi_inited;
- }
- else if (cmp_res > 0)
- {
- if (!last_pos)
- {
- strmov(errmsg,
- "Slave event in first log points past the target position");
- goto err;
- }
- end_io_cache(&log);
- mysql_file_close(file, MYF(MY_WME));
- if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
- MYF(MY_WME)))
- {
- errmsg[0] = 0;
- goto err;
- }
- break;
- }
-
- strmov(last_log_name, linfo.log_file_name);
- last_pos = my_b_tell(&log);
-
- switch (mysql_bin_log.find_next_log(&linfo, 1)) {
- case LOG_INFO_EOF:
- if (last_file >= 0)
- mysql_file_close(last_file, MYF(MY_WME));
- last_file = -1;
- goto found_log;
- case 0:
- break;
- default:
- strmov(errmsg, "Error reading log index");
- goto err;
- }
-
- end_io_cache(&log);
- if (last_file >= 0)
- mysql_file_close(last_file, MYF(MY_WME));
- last_file = file;
- }
-
-found_log:
- my_b_seek(&log, last_pos);
- if (find_target_pos(mi,&log,errmsg))
- goto err;
- fn_format(mi->log_file_name, last_log_name, "","",1); /* Copy basename */
-
-mi_inited:
- error = 0;
-err:
- mysql_mutex_unlock(log_lock);
- end_io_cache(&log);
- mysql_mutex_lock(&LOCK_thread_count);
- thd->current_linfo = 0;
- mysql_mutex_unlock(&LOCK_thread_count);
- if (file >= 0)
- mysql_file_close(file, MYF(MY_WME));
- if (last_file >= 0 && last_file != file)
- mysql_file_close(last_file, MYF(MY_WME));
-
- DBUG_RETURN(error);
-}
-
-
-/**
- Caller must delete result when done.
-*/
-
-static Slave_log_event* find_slave_event(IO_CACHE* log,
- const char* log_file_name,
- char* errmsg)
-{
- Log_event* ev;
- int i;
- bool slave_event_found = 0;
- LINT_INIT(ev);
-
- for (i = 0; i < 2; i++)
- {
- if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*)0, 0)))
- {
- my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
- "Error reading event in log '%s'",
- (char*)log_file_name);
- return 0;
- }
- if (ev->get_type_code() == SLAVE_EVENT)
- {
- slave_event_found = 1;
- break;
- }
- delete ev;
- }
- if (!slave_event_found)
- {
- my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
- "Could not find slave event in log '%s'",
- (char*)log_file_name);
- return 0;
- }
-
- return (Slave_log_event*)ev;
-}
-
-/**
- This function is broken now.
-
- @seealso translate_master()
-*/
-
-bool show_new_master(THD* thd)
-{
- Protocol *protocol= thd->protocol;
- DBUG_ENTER("show_new_master");
- List<Item> field_list;
- char errmsg[SLAVE_ERRMSG_SIZE];
- LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
-
- errmsg[0]=0; // Safety
- if (translate_master(thd, lex_mi, errmsg))
- {
- if (errmsg[0])
- my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
- "SHOW NEW MASTER", errmsg);
- DBUG_RETURN(TRUE);
- }
- else
- {
- field_list.push_back(new Item_empty_string("Log_name", 20));
- field_list.push_back(new Item_return_int("Log_pos", 10,
- MYSQL_TYPE_LONGLONG));
- if (protocol->send_result_set_metadata(&field_list,
- Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
- DBUG_RETURN(TRUE);
- protocol->prepare_for_resend();
- protocol->store(lex_mi->log_file_name, &my_charset_bin);
- protocol->store((ulonglong) lex_mi->pos);
- if (protocol->write())
- DBUG_RETURN(TRUE);
- my_eof(thd);
- DBUG_RETURN(FALSE);
- }
-}
-
-/**
- Asks the master for the list of its other connected slaves.
-
- This is for failsafe replication:
- in order for failsafe replication to work, the servers involved in
- replication must know of each other. We accomplish this by having each
- slave report to the master how to reach it, and on connection, each
- slave receives information about where the other slaves are.
-
- @param mysql pre-existing connection to the master
- @param mi master info
-
- @note
- mi is used only to give detailed error messages which include the
- hostname/port of the master, the username used by the slave to connect to
- the master.
- If the user used by the slave to connect to the master does not have the
- REPLICATION SLAVE privilege, it will pop in this function because
- SHOW SLAVE HOSTS will fail on the master.
-
- @retval
- 1 error
- @retval
- 0 success
-*/
-
-int update_slave_list(MYSQL* mysql, Master_info* mi)
-{
- MYSQL_RES* res=0;
- MYSQL_ROW row;
- const char* error=0;
- bool have_auth_info;
- int port_ind;
- DBUG_ENTER("update_slave_list");
-
- if (mysql_real_query(mysql, STRING_WITH_LEN("SHOW SLAVE HOSTS")) ||
- !(res = mysql_store_result(mysql)))
- {
- error= mysql_error(mysql);
- goto err;
- }
-
- switch (mysql_num_fields(res)) {
- case 5:
- have_auth_info = 0;
- port_ind=2;
- break;
- case 7:
- have_auth_info = 1;
- port_ind=4;
- break;
- default:
- error= "the master returned an invalid number of fields for SHOW SLAVE \
-HOSTS";
- goto err;
- }
-
- mysql_mutex_lock(&LOCK_slave_list);
-
- while ((row= mysql_fetch_row(res)))
- {
- uint32 log_server_id;
- SLAVE_INFO* si, *old_si;
- log_server_id = atoi(row[0]);
- if ((old_si= (SLAVE_INFO*)my_hash_search(&slave_list,
- (uchar*)&log_server_id,4)))
- si = old_si;
- else
- {
- if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
- {
- error= "the slave is out of memory";
- mysql_mutex_unlock(&LOCK_slave_list);
- goto err;
- }
- si->server_id = log_server_id;
- if (my_hash_insert(&slave_list, (uchar*)si))
- {
- error= "the slave is out of memory";
- mysql_mutex_unlock(&LOCK_slave_list);
- goto err;
- }
- }
- strmake(si->host, row[1], sizeof(si->host)-1);
- si->port = atoi(row[port_ind]);
- si->rpl_recovery_rank = atoi(row[port_ind+1]);
- si->master_id = atoi(row[port_ind+2]);
- if (have_auth_info)
- {
- strmake(si->user, row[2], sizeof(si->user)-1);
- strmake(si->password, row[3], sizeof(si->password)-1);
- }
- }
- mysql_mutex_unlock(&LOCK_slave_list);
-
-err:
- if (res)
- mysql_free_result(res);
- if (error)
- {
- sql_print_error("While trying to obtain the list of slaves from the master "
- "'%s:%d', user '%s' got the following error: '%s'",
- mi->host, mi->port, mi->user, error);
- DBUG_RETURN(1);
- }
- DBUG_RETURN(0);
-}
-
/**
Execute a SHOW SLAVE HOSTS statement.
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
index a0c41686696..2ba1f25c591 100644
--- a/sql/repl_failsafe.h
+++ b/sql/repl_failsafe.h
@@ -33,19 +33,12 @@ extern mysql_cond_t COND_rpl_status;
extern TYPELIB rpl_role_typelib;
extern const char* rpl_role_type[], *rpl_status_type[];
-pthread_handler_t handle_failsafe_rpl(void *arg);
void change_rpl_status(ulong from_status, ulong to_status);
int find_recovery_captain(THD* thd, MYSQL* mysql);
-int update_slave_list(MYSQL* mysql, Master_info* mi);
extern HASH slave_list;
-bool load_master_data(THD* thd);
-int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi);
-
-bool show_new_master(THD* thd);
bool show_slave_hosts(THD* thd);
-int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
void init_slave_list();
void end_slave_list();
int register_slave(THD* thd, uchar* packet, uint packet_length);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 27865aee3c2..f31fe6a351d 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -776,7 +776,7 @@ int set_var_password::update(THD *thd)
int set_var_collation_client::check(THD *thd)
{
/* Currently, UCS-2 cannot be used as a client character set */
- if (character_set_client->mbminlen > 1)
+ if (!is_supported_parser_charset(character_set_client))
{
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
character_set_client->csname);
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index a8b0c27d115..998e88704d8 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6394,3 +6394,6 @@ ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX
ER_STMT_CACHE_FULL
eng "Multi-row statements required more than 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try again"
+
+ER_MULTI_UPDATE_KEY_CONFLICT
+ eng "Primary key/partition key update is not allowed since the table is updated both as '%-.192s' and '%-.192s'."
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 22a8f1c4ebf..ca592574e26 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -237,7 +237,6 @@ sp_get_flags_for_command(LEX *lex)
case SQLCOM_SHOW_EVENTS:
case SQLCOM_SHOW_KEYS:
case SQLCOM_SHOW_MASTER_STAT:
- case SQLCOM_SHOW_NEW_MASTER:
case SQLCOM_SHOW_OPEN_TABLES:
case SQLCOM_SHOW_PRIVILEGES:
case SQLCOM_SHOW_PROCESSLIST:
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 427e2eb7346..9c57b3c102d 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -7799,7 +7799,8 @@ public:
Thd_charset_adapter(THD *thd_arg) : thd (thd_arg) {}
bool init_client_charset(uint cs_number)
{
- thd_init_client_charset(thd, cs_number);
+ if (thd_init_client_charset(thd, cs_number))
+ return true;
thd->update_charset();
return thd->is_error();
}
@@ -8929,9 +8930,8 @@ server_mpvio_initialize(THD *thd, MPVIO_EXT *mpvio, uint connect_errors,
mpvio->auth_info.host_or_ip= thd->security_ctx->host_or_ip;
mpvio->auth_info.host_or_ip_length=
(unsigned int) strlen(thd->security_ctx->host_or_ip);
- mpvio->auth_info.user_name= thd->security_ctx->user;
- mpvio->auth_info.user_name_length= thd->security_ctx->user ?
- (unsigned int) strlen(thd->security_ctx->user) : 0;
+ mpvio->auth_info.user_name= NULL;
+ mpvio->auth_info.user_name_length= 0;
mpvio->connect_errors= connect_errors;
mpvio->status= MPVIO_EXT::FAILURE;
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 2333c691240..42a14cda21d 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -370,8 +370,23 @@ void reset_mqh(LEX_USER *lu, bool get_them= 0)
}
-void thd_init_client_charset(THD *thd, uint cs_number)
+/**
+ Set thread character set variables from the given ID
+
+ @param thd thread handle
+ @param cs_number character set and collation ID
+
+ @retval 0 OK; character_set_client, collation_connection and
+ character_set_results are set to the new value,
+ or to the default global values.
+
+ @retval 1 error, e.g. the given ID is not supported by parser.
+ Corresponding SQL error is sent.
+*/
+
+bool thd_init_client_charset(THD *thd, uint cs_number)
{
+ CHARSET_INFO *cs;
/*
Use server character set and collation if
- opt_character_set_client_handshake is not set
@@ -380,10 +395,10 @@ void thd_init_client_charset(THD *thd, uint cs_number)
- client character set doesn't exists in server
*/
if (!opt_character_set_client_handshake ||
- !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
+ !(cs= get_charset(cs_number, MYF(0))) ||
!my_strcasecmp(&my_charset_latin1,
global_system_variables.character_set_client->name,
- thd->variables.character_set_client->name))
+ cs->name))
{
thd->variables.character_set_client=
global_system_variables.character_set_client;
@@ -394,10 +409,18 @@ void thd_init_client_charset(THD *thd, uint cs_number)
}
else
{
+ if (!is_supported_parser_charset(cs))
+ {
+ /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
+ cs->csname);
+ return true;
+ }
thd->variables.character_set_results=
thd->variables.collation_connection=
- thd->variables.character_set_client;
+ thd->variables.character_set_client= cs;
}
+ return false;
}
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index c0cb100c779..1b71d95323d 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -33,7 +33,7 @@ void reset_mqh(LEX_USER *lu, bool get_them);
bool check_mqh(THD *thd, uint check_command);
void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
void decrease_user_connections(USER_CONN *uc);
-void thd_init_client_charset(THD *thd, uint cs_number);
+bool thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd);
bool thd_prepare_connection(THD *thd);
bool thd_is_connection_alive(THD *thd);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 2d11bc7aad7..a9abe174d6e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -162,7 +162,7 @@ enum enum_sql_command {
SQLCOM_SHOW_OPEN_TABLES,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
- SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
+ SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_STORAGE_ENGINES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_HELP, SQLCOM_CREATE_USER, SQLCOM_DROP_USER, SQLCOM_RENAME_USER,
@@ -269,8 +269,7 @@ typedef struct st_lex_server_options
/**
- Structure to hold parameters for CHANGE MASTER or START/STOP SLAVE
- or SHOW NEW MASTER.
+ Structure to hold parameters for CHANGE MASTER, START SLAVE, and STOP SLAVE.
Remark: this should not be confused with Master_info (and perhaps
would better be renamed to st_lex_replication_info). Some fields,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2086100db98..d9e1245bf66 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -316,7 +316,6 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
- sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND;
@@ -2145,19 +2144,6 @@ case SQLCOM_PREPARE:
#endif
break;
}
- case SQLCOM_SHOW_NEW_MASTER:
- {
- if (check_global_access(thd, REPL_SLAVE_ACL))
- goto error;
- /* This query don't work now. See comment in repl_failsafe.cc */
-#ifndef WORKING_NEW_MASTER
- my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
- goto error;
-#else
- res = show_new_master(thd);
- break;
-#endif
- }
#ifdef HAVE_REPLICATION
case SQLCOM_SHOW_SLAVE_HOSTS:
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index c9b0f981d19..9eea07401a2 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -197,4 +197,10 @@ check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables,
bool check_global_access(THD *thd, ulong want_access);
+inline bool is_supported_parser_charset(CHARSET_INFO *cs)
+{
+ return test(cs->mbminlen == 1);
+}
+
+
#endif /* SQL_PARSE_INCLUDED */
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index bc0cca4d887..9783917aaf0 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -1694,23 +1694,6 @@ int reset_master(THD* thd)
return 0;
}
-int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
- const char* log_file_name2, ulonglong log_pos2)
-{
- int res;
- size_t log_file_name1_len= strlen(log_file_name1);
- size_t log_file_name2_len= strlen(log_file_name2);
-
- // We assume that both log names match up to '.'
- if (log_file_name1_len == log_file_name2_len)
- {
- if ((res= strcmp(log_file_name1, log_file_name2)))
- return res;
- return (log_pos1 < log_pos2) ? -1 : (log_pos1 == log_pos2) ? 0 : 1;
- }
- return ((log_file_name1_len < log_file_name2_len) ? -1 : 1);
-}
-
/**
Execute a SHOW BINLOG EVENTS statement.
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 4d3b0b8d62c..dfe41d8e688 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -43,8 +43,6 @@ int start_slave(THD* thd, Master_info* mi, bool net_report);
int stop_slave(THD* thd, Master_info* mi, bool net_report);
bool change_master(THD* thd, Master_info* mi);
bool mysql_show_binlog_events(THD* thd);
-int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
- const char* log_file_name2, ulonglong log_pos2);
int reset_slave(THD *thd, Master_info* mi);
int reset_master(THD* thd);
bool purge_master_logs(THD* thd, const char* to_log);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3d073cf777e..3173b6c1a0e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -307,61 +307,65 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
}
-/*
+/**
Fix fields referenced from inner selects.
- SYNOPSIS
- fix_inner_refs()
- thd Thread handle
- 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)
+ @param thd Thread handle
+ @param all_fields List of all fields used in select
+ @param select Current select
+ @param ref_pointer_array Array of references to Items used in current select
+ @param group_list GROUP BY list (is NULL by default)
- DESCRIPTION
- The function serves 3 purposes - adds fields referenced from inner
- selects to the current select list, resolves which class to use
- to access referenced item (Item_ref of Item_direct_ref) and fixes
- references (Item_ref objects) to these fields.
+ @details
+ The function serves 3 purposes
+
+ - adds fields referenced from inner query blocks to the current select list
+
+ - Decides which class to use to reference the items (Item_ref or
+ Item_direct_ref)
- If a field isn't already in the select list and the ref_pointer_array
+ - fixes references (Item_ref objects) to these fields.
+
+ If a field isn't already on the select list and the ref_pointer_array
is provided then it is added to the all_fields list and the pointer to
it is saved in the ref_pointer_array.
The class to access the outer field is determined by the following rules:
- 1. If the outer field isn't used under an aggregate function
- then the Item_ref class should be used.
- 2. If the outer field is used under an aggregate function and this
- 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.
+
+ -#. If the outer field isn't used under an aggregate function then the
+ Item_ref class should be used.
+
+ -#. If the outer field is used under an aggregate function and this
+ function is, in turn, aggregated in the query block where the outer
+ field was resolved or some query nested therein, 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.
+ it can be done only after aggregate functions are fixed and pulled up to
+ selects where they are to be aggregated.
+
When the class is chosen it substitutes the original field in the
Item_outer_ref object.
After this we proceed with fixing references (Item_outer_ref objects) to
this field from inner subqueries.
- RETURN
- TRUE an error occured
- FALSE ok
-*/
+ @return Status
+ @retval true An error occured.
+ @retval false OK.
+ */
bool
fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
Item **ref_pointer_array, ORDER *group_list)
{
Item_outer_ref *ref;
- bool res= FALSE;
- bool direct_ref= FALSE;
List_iterator<Item_outer_ref> ref_it(select->inner_refs_list);
while ((ref= ref_it++))
{
+ bool direct_ref= false;
Item *item= ref->outer_ref;
Item **item_ref= ref->ref;
Item_ref *new_ref;
@@ -433,7 +437,7 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
return TRUE;
thd->used_tables|= item->used_tables();
}
- return res;
+ return false;
}
/**
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index d19b876a82f..66f293a82c6 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -252,8 +252,8 @@ bool String::copy_aligned(const char *str,uint32 arg_length, uint32 offset,
CHARSET_INFO *cs)
{
/* How many bytes are in incomplete character */
- offset= cs->mbmaxlen - offset; /* How many zeros we should prepend */
- DBUG_ASSERT(offset && offset != cs->mbmaxlen);
+ offset= cs->mbminlen - offset; /* How many zeros we should prepend */
+ DBUG_ASSERT(offset && offset != cs->mbminlen);
uint32 aligned_length= arg_length + offset;
if (alloc(aligned_length))
diff --git a/sql/sql_string.h b/sql/sql_string.h
index dcd9975f399..67c8fe4f45f 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -113,6 +113,9 @@ public:
inline const char *ptr() const { return Ptr; }
inline char *c_ptr()
{
+ DBUG_ASSERT(!alloced || !Ptr || !Alloced_length ||
+ (Alloced_length >= (str_length + 1)));
+
if (!Ptr || Ptr[str_length]) /* Should be safe */
(void) realloc(str_length);
return Ptr;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 08d804efcb6..59356540201 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -998,6 +998,98 @@ static table_map get_table_map(List<Item> *items)
return map;
}
+/**
+ If one row is updated through two different aliases and the first
+ update physically moves the row, the second update will error
+ because the row is no longer located where expected. This function
+ checks if the multiple-table update is about to do that and if so
+ returns with an error.
+
+ The following update operations physically moves rows:
+ 1) Update of a column in a clustered primary key
+ 2) Update of a column used to calculate which partition the row belongs to
+
+ This function returns with an error if both of the following are
+ true:
+
+ a) A table in the multiple-table update statement is updated
+ through multiple aliases (including views)
+ b) At least one of the updates on the table from a) may physically
+ moves the row. Note: Updating a column used to calculate which
+ partition a row belongs to does not necessarily mean that the
+ row is moved. The new value may or may not belong to the same
+ partition.
+
+ @param leaves First leaf table
+ @param tables_for_update Map of tables that are updated
+
+ @return
+ true if the update is unsafe, in which case an error message is also set,
+ false otherwise.
+*/
+static
+bool unsafe_key_update(TABLE_LIST *leaves, table_map tables_for_update)
+{
+ TABLE_LIST *tl= leaves;
+
+ for (tl= leaves; tl ; tl= tl->next_leaf)
+ {
+ if (tl->table->map & tables_for_update)
+ {
+ TABLE *table1= tl->table;
+ bool primkey_clustered= (table1->file->primary_key_is_clustered() &&
+ table1->s->primary_key != MAX_KEY);
+
+ bool table_partitioned= false;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ table_partitioned= (table1->part_info != NULL);
+#endif
+
+ if (!table_partitioned && !primkey_clustered)
+ continue;
+
+ for (TABLE_LIST* tl2= tl->next_leaf; tl2 ; tl2= tl2->next_leaf)
+ {
+ /*
+ Look at "next" tables only since all previous tables have
+ already been checked
+ */
+ TABLE *table2= tl2->table;
+ if (table2->map & tables_for_update && table1->s == table2->s)
+ {
+ // A table is updated through two aliases
+ if (table_partitioned &&
+ (partition_key_modified(table1, table1->write_set) ||
+ partition_key_modified(table2, table2->write_set)))
+ {
+ // Partitioned key is updated
+ my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0),
+ tl->belong_to_view ? tl->belong_to_view->alias
+ : tl->alias,
+ tl2->belong_to_view ? tl2->belong_to_view->alias
+ : tl2->alias);
+ return true;
+ }
+
+ if (primkey_clustered &&
+ (bitmap_is_set(table1->write_set, table1->s->primary_key) ||
+ bitmap_is_set(table2->write_set, table2->s->primary_key)))
+ {
+ // Clustered primary key is updated
+ my_error(ER_MULTI_UPDATE_KEY_CONFLICT, MYF(0),
+ tl->belong_to_view ? tl->belong_to_view->alias
+ : tl->alias,
+ tl2->belong_to_view ? tl2->belong_to_view->alias
+ : tl2->alias);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
/*
make update specific preparation and checks after opening tables
@@ -1077,10 +1169,14 @@ int mysql_multi_update_prepare(THD *thd)
thd->table_map_for_update= tables_for_update= get_table_map(fields);
+ leaves= lex->select_lex.leaf_tables;
+
+ if (unsafe_key_update(leaves, tables_for_update))
+ DBUG_RETURN(true);
+
/*
Setup timestamp handling and locking mode
*/
- leaves= lex->select_lex.leaf_tables;
for (tl= leaves; tl; tl= tl->next_leaf)
{
TABLE *table= tl->table;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 397afd26d8d..02e0d347ef7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -10921,19 +10921,6 @@ show_param:
if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
MYSQL_YYABORT;
}
- | NEW_SYM MASTER_SYM FOR_SYM SLAVE
- WITH MASTER_LOG_FILE_SYM EQ
- TEXT_STRING_sys /* $8 */
- AND_SYM MASTER_LOG_POS_SYM EQ
- ulonglong_num /* $12 */
- AND_SYM MASTER_SERVER_ID_SYM EQ
- ulong_num /* $16 */
- {
- Lex->sql_command = SQLCOM_SHOW_NEW_MASTER;
- Lex->mi.log_file_name = $8.str;
- Lex->mi.pos = $12;
- Lex->mi.server_id = $16;
- }
| master_or_binary LOGS_SYM
{
Lex->sql_command = SQLCOM_SHOW_BINLOGS;
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index ce1dcb4a33c..612ce48de0b 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3082,7 +3082,7 @@ static bool check_locale(sys_var *self, THD *thd, set_var *var)
String str(buff, sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
return true;
- else if (!(locale= my_locale_by_name(res->c_ptr())))
+ else if (!(locale= my_locale_by_name(res->c_ptr_safe())))
{
ErrConvString err(res);
my_error(ER_UNKNOWN_LOCALE, MYF(0), err.ptr());
diff --git a/sql/transaction.cc b/sql/transaction.cc
index b331fea89fe..85686810893 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2008 Sun/MySQL
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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
@@ -635,8 +635,9 @@ bool trans_xa_commit(THD *thd)
if (xa_trans_rolled_back(&thd->transaction.xid_state))
{
- if ((res= test(ha_rollback_trans(thd, TRUE))))
+ if (ha_rollback_trans(thd, TRUE))
my_error(ER_XAER_RMERR, MYF(0));
+ res= thd->is_error();
}
else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
{