diff options
author | unknown <tsmith@maint1.mysql.com> | 2007-06-21 20:55:37 +0200 |
---|---|---|
committer | unknown <tsmith@maint1.mysql.com> | 2007-06-21 20:55:37 +0200 |
commit | 2da92ead65f1bf6189e556d42fe9a11108ef343e (patch) | |
tree | 9396a2750231f593b88b423264adf6f3b7ba6af9 /sql | |
parent | a1c0a4b45d5d60322e8615ae7407e90cfcebb576 (diff) | |
parent | 8ddf61d382cf98ab8adc23c04c0aced95bc4f4ef (diff) | |
download | mariadb-git-2da92ead65f1bf6189e556d42fe9a11108ef343e.tar.gz |
Merge maint1.mysql.com:/data/localhome/tsmith/bk/maint/50
into maint1.mysql.com:/data/localhome/tsmith/bk/maint/51
configure.in:
Auto merged
include/m_ctype.h:
Auto merged
mysql-test/Makefile.am:
Auto merged
mysql-test/t/innodb.test:
Auto merged
mysys/charset-def.c:
Auto merged
mysys/charset.c:
Auto merged
sql/log_event.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_class.cc:
Auto merged
strings/ctype-big5.c:
Auto merged
strings/ctype-gbk.c:
Auto merged
strings/ctype-sjis.c:
Auto merged
strings/ctype-uca.c:
Auto merged
strings/ctype.c:
Auto merged
mysql-test/r/innodb.result:
Manual merge
mysql-test/r/multi_update.result:
Manual merge
mysql-test/t/multi_update.test:
Manual merge
sql/sql_update.cc:
SCCS merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_acl.cc | 8 | ||||
-rw-r--r-- | sql/sql_class.cc | 59 | ||||
-rw-r--r-- | sql/sql_update.cc | 90 |
3 files changed, 135 insertions, 22 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1b57e9363e4..dfdd6f5c5b4 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5539,6 +5539,12 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); + if (result) + my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); + + DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno)); + DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error)); + if (mysql_bin_log.is_open()) { thd->binlog_query(THD::MYSQL_QUERY_TYPE, @@ -5547,8 +5553,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); DBUG_RETURN(result); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 62f6706d717..e83432519d4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1457,6 +1457,11 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u) } +#define NEED_ESCAPING(x) ((int) (uchar) (x) == escape_char || \ + (int) (uchar) (x) == field_sep_char || \ + (int) (uchar) (x) == line_sep_char || \ + !(x)) + bool select_export::send_data(List<Item> &items) { @@ -1516,14 +1521,20 @@ bool select_export::send_data(List<Item> &items) used_length=res->length(); if (result_type == STRING_RESULT && escape_char != -1) { - char *pos,*start,*end; - + char *pos, *start, *end; + CHARSET_INFO *res_charset= res->charset(); + CHARSET_INFO *character_set_client= thd->variables. + character_set_client; + bool check_second_byte= (res_charset == &my_charset_bin) && + character_set_client-> + escape_with_backslash_is_dangerous; + DBUG_ASSERT(character_set_client->mbmaxlen == 2 || + !character_set_client->escape_with_backslash_is_dangerous); for (start=pos=(char*) res->ptr(),end=pos+used_length ; pos != end ; pos++) { #ifdef USE_MB - CHARSET_INFO *res_charset=res->charset(); if (use_mb(res_charset)) { int l; @@ -1534,9 +1545,45 @@ bool select_export::send_data(List<Item> &items) } } #endif - if ((int) *pos == escape_char || (int) *pos == field_sep_char || - (int) *pos == line_sep_char || !*pos) - { + + /* + Special case when dumping BINARY/VARBINARY/BLOB values + for the clients with character sets big5, cp932, gbk and sjis, + which can have the escape character (0x5C "\" by default) + as the second byte of a multi-byte sequence. + + If + - pos[0] is a valid multi-byte head (e.g 0xEE) and + - pos[1] is 0x00, which will be escaped as "\0", + + then we'll get "0xEE + 0x5C + 0x30" in the output file. + + If this file is later loaded using this sequence of commands: + + mysql> create table t1 (a varchar(128)) character set big5; + mysql> LOAD DATA INFILE 'dump.txt' INTO TABLE t1; + + then 0x5C will be misinterpreted as the second byte + of a multi-byte character "0xEE + 0x5C", instead of + escape character for 0x00. + + To avoid this confusion, we'll escape the multi-byte + head character too, so the sequence "0xEE + 0x00" will be + dumped as "0x5C + 0xEE + 0x5C + 0x30". + + Note, in the condition below we only check if + mbcharlen is equal to 2, because there are no + character sets with mbmaxlen longer than 2 + and with escape_with_backslash_is_dangerous set. + DBUG_ASSERT before the loop makes that sure. + */ + + if (NEED_ESCAPING(*pos) || + (check_second_byte && + my_mbcharlen(character_set_client, (uchar) *pos) == 2 && + pos + 1 < end && + NEED_ESCAPING(pos[1]))) + { char tmp_buff[2]; tmp_buff[0]= escape_char; tmp_buff[1]= *pos ? *pos : '0'; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d9bf6b4d918..33ec8152837 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1069,6 +1069,7 @@ bool mysql_multi_update(THD *thd, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) { multi_update *result; + bool res; DBUG_ENTER("mysql_multi_update"); if (!(result= new multi_update(table_list, @@ -1083,7 +1084,7 @@ bool mysql_multi_update(THD *thd, MODE_STRICT_ALL_TABLES)); List<Item> total_list; - (void) mysql_select(thd, &select_lex->ref_pointer_array, + 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, @@ -1091,6 +1092,15 @@ bool mysql_multi_update(THD *thd, 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, + thd->net.report_error)); + res|= thd->net.report_error; + if (unlikely(res)) + { + /* If we had a another error reported earlier then this will be ignored */ + result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); + result->abort(); + } delete result; thd->abort_on_warning= 0; DBUG_RETURN(FALSE); @@ -1441,8 +1451,9 @@ multi_update::~multi_update() if (copy_field) delete [] copy_field; thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting - if (!trans_safe) + if (!trans_safe) // todo: remove since redundant thd->no_trans_update.all= TRUE; + DBUG_ASSERT(trans_safe || thd->no_trans_update.all); } @@ -1531,8 +1542,15 @@ bool multi_update::send_data(List<Item> ¬_used_values) } else { - if (!table->file->has_transactions()) + /* non-transactional or transactional table got modified */ + /* either multi_update class' flag is raised in its branch */ + if (table->file->has_transactions()) + transactional_tables= 1; + else + { + trans_safe= 0; thd->no_trans_update.stmt= TRUE; + } if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)) @@ -1589,8 +1607,8 @@ void multi_update::send_error(uint errcode,const char *err) my_error(errcode, MYF(0), err); /* If nothing updated return */ - if (!updated) - return; + if (updated == 0) /* the counter might be reset in send_eof */ + return; /* and then the query has been binlogged */ /* Something already updated so we have to invalidate cache */ query_cache_invalidate3(thd, update_tables, 1); @@ -1601,11 +1619,43 @@ void multi_update::send_error(uint errcode,const char *err) */ if (trans_safe) - ha_rollback_stmt(thd); - else if (do_update && table_count > 1) { - /* Add warning here */ - VOID(do_updates(0)); + DBUG_ASSERT(transactional_tables); + (void) ha_autocommit_or_rollback(thd, 1); + } + else + { + DBUG_ASSERT(thd->no_trans_update.stmt); + if (do_update && table_count > 1) + { + /* Add warning here */ + /* + todo/fixme: do_update() is never called with the arg 1. + should it change the signature to become argless? + */ + VOID(do_updates(0)); + } + } + if (thd->no_trans_update.stmt) + { + /* + The query has to binlog because there's a modified non-transactional table + either from the query's list or via a stored routine: bug#13270,23333 + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + if (!trans_safe) + thd->no_trans_update.all= TRUE; + } + DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt); + + if (transactional_tables) + { + (void) ha_autocommit_or_rollback(thd, 1); } } @@ -1736,9 +1786,12 @@ int multi_update::do_updates(bool from_send_error) if (updated != org_updated) { if (table->file->has_transactions()) - transactional_tables= 1; + transactional_tables= 1; else - trans_safe= 0; // Can't do safe rollback + { + trans_safe= 0; // Can't do safe rollback + thd->no_trans_update.stmt= TRUE; + } } (void) table->file->ha_rnd_end(); (void) tmp_table->file->ha_rnd_end(); @@ -1768,7 +1821,10 @@ err2: if (table->file->has_transactions()) transactional_tables= 1; else + { trans_safe= 0; + thd->no_trans_update.stmt= TRUE; + } } DBUG_RETURN(1); } @@ -1798,14 +1854,20 @@ bool multi_update::send_eof() Write the SQL statement to the binlog if we updated rows and we succeeded or if we updated some non transactional tables. + + The query has to binlog because there's a modified non-transactional table + either from the query's list or via a stored routine: bug#13270,23333 */ - if ((local_error == 0) || (updated && !trans_safe)) + DBUG_ASSERT(trans_safe || !updated || thd->no_trans_update.stmt); + if (local_error == 0 || thd->no_trans_update.stmt) { if (mysql_bin_log.is_open()) { if (local_error == 0) thd->clear_error(); + else + updated= 0; /* if there's an error binlog it here not in ::send_error */ if (thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, transactional_tables, FALSE) && @@ -1814,7 +1876,7 @@ bool multi_update::send_eof() local_error= 1; // Rollback update } } - if (!transactional_tables) + if (!trans_safe) thd->no_trans_update.all= TRUE; } @@ -1826,7 +1888,7 @@ bool multi_update::send_eof() if (local_error > 0) // if the above log write did not fail ... { - /* Safety: If we haven't got an error before (should not happen) */ + /* Safety: If we haven't got an error before (can happen in do_updates) */ my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update", MYF(0)); return TRUE; |