From: Date: July 12 2006 10:19pm Subject: bk commit into 5.1 tree (kostja:1.2243) List-Archive: http://lists.mysql.com/commits/9099 Message-Id: <20060712201922.2E11E1033@bodhi.local> Below is the list of changes that have just been committed into a local 5.1 repository of kostja. When kostja does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2006-07-13 00:18:59+04:00, kostja@stripped +14 -0 Merge bk-internal.mysql.com:/home/bk/mysql-5.1 into bodhi.local:/opt/local/work/mysql-5.1-runtime-merge MERGE: 1.2239.1.11 mysql-test/r/federated.result@stripped, 2006-07-13 00:18:53+04:00, kostja@stripped +0 -0 Manual merge. MERGE: 1.30.1.4 mysql-test/t/federated.test@stripped, 2006-07-13 00:18:53+04:00, kostja@stripped +64 -13 Manual merge. MERGE: 1.26.1.4 sql/ha_ndbcluster.cc@stripped, 2006-07-13 00:15:02+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.336.1.6 sql/ha_partition.cc@stripped, 2006-07-13 00:15:02+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.60.1.1 sql/log_event.cc@stripped, 2006-07-13 00:15:02+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.232.1.2 sql/mysql_priv.h@stripped, 2006-07-13 00:15:03+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.416.1.2 sql/sql_delete.cc@stripped, 2006-07-13 00:15:03+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.186.1.1 sql/sql_insert.cc@stripped, 2006-07-13 00:18:53+04:00, kostja@stripped +5 -5 Manual merge. MERGE: 1.208.1.2 sql/sql_load.cc@stripped, 2006-07-13 00:15:03+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.100.1.1 sql/sql_parse.cc@stripped, 2006-07-13 00:15:04+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.565.1.5 sql/sql_table.cc@stripped, 2006-07-13 00:15:04+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.356.1.1 sql/sql_trigger.cc@stripped, 2006-07-13 00:15:04+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.56.1.2 sql/sql_update.cc@stripped, 2006-07-13 00:15:04+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.198.1.1 sql/table.cc@stripped, 2006-07-13 00:15:05+04:00, kostja@stripped +0 -0 Auto merged MERGE: 1.227.1.1 # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: kostja # Host: bodhi.local # Root: /opt/local/work/mysql-5.1-runtime-merge/RESYNC --- 1.234/sql/log_event.cc 2006-07-13 00:19:17 +04:00 +++ 1.235/sql/log_event.cc 2006-07-13 00:19:17 +04:00 @@ -1934,6 +1934,16 @@ end: thd->query_length= 0; VOID(pthread_mutex_unlock(&LOCK_thread_count)); close_thread_tables(thd); + /* + As a disk space optimization, future masters will not log an event for + LAST_INSERT_ID() if that function returned 0 (and thus they will be able + to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt + variable by (THD->first_successful_insert_id_in_prev_stmt > 0) ; with the + resetting below we are ready to support that. + */ + thd->first_successful_insert_id_in_prev_stmt_for_binlog= 0; + thd->first_successful_insert_id_in_prev_stmt= 0; + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); /* If there was an error we stop. Otherwise we increment positions. Note that @@ -3425,11 +3435,11 @@ int Intvar_log_event::exec_event(struct { switch (type) { case LAST_INSERT_ID_EVENT: - thd->last_insert_id_used = 1; - thd->last_insert_id = val; + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1; + thd->first_successful_insert_id_in_prev_stmt= val; break; case INSERT_ID_EVENT: - thd->next_insert_id = val; + thd->force_one_auto_inc_interval(val); break; } rli->inc_event_relay_log_pos(); @@ -5353,10 +5363,10 @@ int Rows_log_event::exec_event(st_relay_ /* lock_tables() reads the contents of thd->lex, so they must be - initialized, so we should call lex_start(); to be even safer, we - call mysql_init_query() which does a more complete set of inits. + initialized. Contrary to in Table_map_log_event::exec_event() we don't + call mysql_init_query() as that may reset the binlog format. */ - mysql_init_query(thd, NULL, 0); + lex_start(thd, NULL, 0); while ((error= lock_tables(thd, rli->tables_to_lock, rli->tables_to_lock_count, &need_reopen))) @@ -5860,6 +5870,12 @@ int Table_map_log_event::exec_event(st_r else { /* + open_tables() reads the contents of thd->lex, so they must be + initialized, so we should call lex_start(); to be even safer, we + call mysql_init_query() which does a more complete set of inits. + */ + mysql_init_query(thd, NULL, 0); + /* Check if the slave is set to use SBR. If so, it should switch to using RBR until the end of the "statement", i.e., next STMT_END_F or next error. @@ -5875,12 +5891,6 @@ int Table_map_log_event::exec_event(st_r Note that for any table that should not be replicated, a filter is needed. */ uint count; - /* - open_tables() reads the contents of thd->lex, so they must be - initialized, so we should call lex_start(); to be even safer, we - call mysql_init_query() which does a more complete set of inits. - */ - mysql_init_query(thd, NULL, 0); if ((error= open_tables(thd, &table_list, &count, 0))) { if (thd->query_error || thd->is_fatal_error) --- 1.419/sql/mysql_priv.h 2006-07-13 00:19:17 +04:00 +++ 1.420/sql/mysql_priv.h 2006-07-13 00:19:17 +04:00 @@ -1970,6 +1970,17 @@ inline int hexchar_to_int(char c) } /* + is_user_table() + return true if the table was created explicitly +*/ + +inline bool is_user_table(TABLE * table) +{ + const char *name= table->s->table_name.str; + return strncmp(name, tmp_file_prefix, tmp_file_prefix_length); +} + +/* Some functions that are different in the embedded library and the normal server */ --- 1.187/sql/sql_delete.cc 2006-07-13 00:19:17 +04:00 +++ 1.188/sql/sql_delete.cc 2006-07-13 00:19:17 +04:00 @@ -986,12 +986,12 @@ trunc_by_del: thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT); ha_enable_transaction(thd, FALSE); mysql_init_select(thd->lex); -#ifdef HAVE_ROW_BASED_REPLICATION + bool save_binlog_row_based= thd->current_stmt_binlog_row_based; thd->clear_current_stmt_binlog_row_based(); -#endif error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, HA_POS_ERROR, LL(0), TRUE); ha_enable_transaction(thd, TRUE); thd->options= save_options; + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(error); } --- 1.211/sql/sql_insert.cc 2006-07-13 00:19:18 +04:00 +++ 1.212/sql/sql_insert.cc 2006-07-13 00:19:18 +04:00 @@ -219,9 +219,6 @@ static int check_insert_fields(THD *thd, } } } - if (table->found_next_number_field) - table->mark_auto_increment_column(); - table->mark_columns_needed_for_insert(); // For the values we need select_priv #ifndef NO_EMBEDDED_ACCESS_CHECKS table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); @@ -451,6 +448,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *t thd->proc_info="update"; if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if (duplic == DUP_REPLACE && + (!table->triggers || !table->triggers->has_delete_triggers())) + table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); /* let's *try* to start bulk inserts. It won't necessary start them as values_list.elements should be greater than @@ -479,6 +479,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t error= 1; } + table->mark_columns_needed_for_insert(); + if (table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)) error= 1; @@ -653,6 +655,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *t thd->count_cuted_fields= CHECK_FIELD_IGNORE; if (duplic != DUP_ERROR || ignore) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + if (duplic == DUP_REPLACE && + (!table->triggers || !table->triggers->has_delete_triggers())) + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); if (error) goto abort; @@ -2037,9 +2042,8 @@ bool delayed_insert::handle_inserts(void { int error; ulong max_rows; - bool using_ignore=0, - using_bin_log= mysql_bin_log.is_open(); - + bool using_ignore= 0, using_opt_replace= 0, + using_bin_log= mysql_bin_log.is_open(); delayed_row *row; DBUG_ENTER("handle_inserts"); @@ -2098,6 +2102,13 @@ bool delayed_insert::handle_inserts(void table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); using_ignore=1; } + if (info.handle_duplicates == DUP_REPLACE && + (!table->triggers || + !table->triggers->has_delete_triggers())) + { + table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); + using_opt_replace= 1; + } thd.clear_error(); // reset error for binlog if (write_record(&thd, table, &info)) { @@ -2111,6 +2122,11 @@ bool delayed_insert::handle_inserts(void using_ignore=0; table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); } + if (using_opt_replace) + { + using_opt_replace= 0; + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); + } if (row->log_query && row->query.str != NULL && mysql_bin_log.is_open()) { @@ -2384,6 +2400,9 @@ select_insert::prepare(List &value thd->cuted_fields=0; if (info.ignore || info.handle_duplicates != DUP_ERROR) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if (info.handle_duplicates == DUP_REPLACE && + (!table->triggers || !table->triggers->has_delete_triggers())) + table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); thd->no_trans_update= 0; thd->abort_on_warning= (!info.ignore && (thd->variables.sql_mode & @@ -2393,6 +2412,10 @@ select_insert::prepare(List &value check_that_all_fields_are_given_values(thd, table, table_list)) || table_list->prepare_where(thd, 0, TRUE) || table_list->prepare_check_option(thd)); + + if (!res) + table->mark_columns_needed_for_insert(); + DBUG_RETURN(res); } @@ -2587,6 +2610,7 @@ bool select_insert::send_eof() error= (!thd->prelocked_mode) ? table->file->ha_end_bulk_insert():0; table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); if (info.copied || info.deleted || info.updated) { @@ -2861,6 +2885,9 @@ select_create::prepare(List &value thd->cuted_fields=0; if (info.ignore || info.handle_duplicates != DUP_ERROR) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + if (info.handle_duplicates == DUP_REPLACE && + (!table->triggers || !table->triggers->has_delete_triggers())) + table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); if (!thd->prelocked_mode) table->file->ha_start_bulk_insert((ha_rows) 0); thd->no_trans_update= 0; @@ -2868,8 +2895,10 @@ select_create::prepare(List &value (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))); - DBUG_RETURN(check_that_all_fields_are_given_values(thd, table, - table_list)); + if (check_that_all_fields_are_given_values(thd, table, table_list)) + DBUG_RETURN(1); + table->mark_columns_needed_for_insert(); + DBUG_RETURN(0); } @@ -2943,6 +2972,7 @@ bool select_create::send_eof() else { table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); VOID(pthread_mutex_lock(&LOCK_open)); mysql_unlock_tables(thd, thd->extra_lock); if (!table->s->tmp_table) @@ -2968,6 +2998,7 @@ void select_create::abort() if (table) { table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); handlerton *table_type=table->s->db_type; if (!table->s->tmp_table) { --- 1.102/sql/sql_load.cc 2006-07-13 00:19:18 +04:00 +++ 1.103/sql/sql_load.cc 2006-07-13 00:19:18 +04:00 @@ -501,13 +501,12 @@ bool mysql_load(THD *thd,sql_exchange *e error=ha_autocommit_or_rollback(thd,error); err: + table->file->ha_release_auto_increment(); if (thd->lock) { mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - if (table != NULL) - table->file->release_auto_increment(); thd->abort_on_warning= 0; DBUG_RETURN(error); } @@ -643,14 +642,6 @@ read_fixed_length(THD *thd, COPY_INFO &i thd->no_trans_update= no_trans_update; /* - If auto_increment values are used, save the first one - for LAST_INSERT_ID() and for the binary/update log. - We can't use insert_id() as we don't want to touch the - last_insert_id_used flag. - */ - if (!id && thd->insert_id_used) - id= thd->last_insert_id; - /* We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. */ @@ -666,8 +657,6 @@ read_fixed_length(THD *thd, COPY_INFO &i thd->row_count++; continue_loop:; } - if (id && !read_info.error) - thd->insert_id(id); // For binary/update log DBUG_RETURN(test(read_info.error)); } @@ -811,14 +800,6 @@ read_sep_field(THD *thd, COPY_INFO &info if (write_record(thd, table, &info)) DBUG_RETURN(1); /* - If auto_increment values are used, save the first one - for LAST_INSERT_ID() and for the binary/update log. - We can't use insert_id() as we don't want to touch the - last_insert_id_used flag. - */ - if (!id && thd->insert_id_used) - id= thd->last_insert_id; - /* We don't need to reset auto-increment field since we are restoring its default value at the beginning of each loop iteration. */ @@ -837,8 +818,6 @@ read_sep_field(THD *thd, COPY_INFO &info thd->row_count++; continue_loop:; } - if (id && !read_info.error) - thd->insert_id(id); // For binary/update log DBUG_RETURN(test(read_info.error)); } --- 1.567/sql/sql_parse.cc 2006-07-13 00:19:20 +04:00 +++ 1.568/sql/sql_parse.cc 2006-07-13 00:19:20 +04:00 @@ -818,6 +818,37 @@ static void reset_mqh(LEX_USER *lu, bool #endif /* NO_EMBEDDED_ACCESS_CHECKS */ } +void thd_init_client_charset(THD *thd, uint cs_number) +{ + /* + Use server character set and collation if + - opt_character_set_client_handshake is not set + - client has not specified a character set + - client character set is the same as the servers + - 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))) || + !my_strcasecmp(&my_charset_latin1, + global_system_variables.character_set_client->name, + thd->variables.character_set_client->name)) + { + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.character_set_results= + global_system_variables.character_set_results; + } + else + { + thd->variables.character_set_results= + thd->variables.collation_connection= + thd->variables.character_set_client; + } +} + + /* Perform handshake, authorize client and update thd ACL variables. SYNOPSIS @@ -953,33 +984,7 @@ static int check_connection(THD *thd) thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; thd->max_client_packet_length= uint4korr(net->read_pos+4); DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); - /* - Use server character set and collation if - - opt_character_set_client_handshake is not set - - client has not specified a character set - - client character set is the same as the servers - - client character set doesn't exists in server - */ - if (!opt_character_set_client_handshake || - !(thd->variables.character_set_client= - get_charset((uint) net->read_pos[8], MYF(0))) || - !my_strcasecmp(&my_charset_latin1, - global_system_variables.character_set_client->name, - thd->variables.character_set_client->name)) - { - thd->variables.character_set_client= - global_system_variables.character_set_client; - thd->variables.collation_connection= - global_system_variables.collation_connection; - thd->variables.character_set_results= - global_system_variables.character_set_results; - } - else - { - thd->variables.character_set_results= - thd->variables.collation_connection= - thd->variables.character_set_client; - } + thd_init_client_charset(thd, (uint) net->read_pos[8]); thd->update_charset(); end= (char*) net->read_pos+32; } @@ -2558,11 +2563,6 @@ mysql_execute_command(THD *thd) statistic_increment(thd->status_var.com_stat[lex->sql_command], &LOCK_status); -#ifdef HAVE_ROW_BASED_REPLICATION - if (lex->binlog_row_based_if_mixed) - thd->set_current_stmt_binlog_row_based_if_mixed(); -#endif /*HAVE_ROW_BASED_REPLICATION*/ - switch (lex->sql_command) { case SQLCOM_SHOW_EVENTS: if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, @@ -3112,6 +3112,12 @@ end_with_restore_list: } } /* Don't yet allow changing of symlinks with ALTER TABLE */ + if (lex->create_info.data_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "DATA DIRECTORY option ignored"); + if (lex->create_info.index_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "INDEX DIRECTORY option ignored"); lex->create_info.data_file_name=lex->create_info.index_file_name=0; /* ALTER TABLE ends previous transaction */ if (end_active_trans(thd)) @@ -3382,8 +3388,9 @@ end_with_restore_list: res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore); + /* do not show last insert ID if VIEW does not have auto_inc */ if (first_table->view && !first_table->contain_auto_increment) - thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it + thd->first_successful_insert_id_in_cur_stmt= 0; break; } case SQLCOM_REPLACE_SELECT: @@ -3443,9 +3450,9 @@ end_with_restore_list: /* revert changes for SP */ select_lex->table_list.first= (byte*) first_table; } - + /* do not show last insert ID if VIEW does not have auto_inc */ if (first_table->view && !first_table->contain_auto_increment) - thd->last_insert_id= 0; // do not show last insert ID if VIEW have not it + thd->first_successful_insert_id_in_cur_stmt= 0; break; } case SQLCOM_TRUNCATE: @@ -5189,9 +5196,6 @@ end: */ if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) reset_one_shot_variables(thd); -#ifdef HAVE_ROW_BASED_REPLICATION - thd->reset_current_stmt_binlog_row_based(); -#endif /*HAVE_ROW_BASED_REPLICATION*/ /* The return value for ROW_COUNT() is "implementation dependent" if the @@ -5823,6 +5827,7 @@ mysql_init_query(THD *thd, uchar *buf, u DESCRIPTION This needs to be called before execution of every statement (prepared or conventional). + It is not called by substatements of routines. TODO Make it a method of THD and align its name with the rest of @@ -5833,9 +5838,12 @@ mysql_init_query(THD *thd, uchar *buf, u void mysql_reset_thd_for_next_command(THD *thd) { DBUG_ENTER("mysql_reset_thd_for_next_command"); + DBUG_ASSERT(!thd->spcont); /* not for substatements of routines */ thd->free_list= 0; thd->select_number= 1; - thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; + thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty(); + thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= + thd->query_start_used= 0; thd->is_fatal_error= thd->time_zone_used= 0; thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | @@ -5862,6 +5870,12 @@ void mysql_reset_thd_for_next_command(TH thd->rand_used= 0; thd->sent_row_count= thd->examined_row_count= 0; } + /* + Because we come here only for start of top-statements, binlog format is + constant inside a complex statement (using stored functions) etc. + */ + thd->reset_current_stmt_binlog_row_based(); + DBUG_VOID_RETURN; } --- 1.357/sql/sql_table.cc 2006-07-13 00:19:21 +04:00 +++ 1.358/sql/sql_table.cc 2006-07-13 00:19:21 +04:00 @@ -4964,7 +4964,6 @@ bool mysql_alter_table(THD *thd,char *ne char path[FN_REFLEN]; char reg_path[FN_REFLEN+1]; ha_rows copied,deleted; - ulonglong next_insert_id; uint db_create_options, used_fields; handlerton *old_db_type, *new_db_type; HA_CREATE_INFO *create_info; @@ -5784,7 +5783,6 @@ bool mysql_alter_table(THD *thd,char *ne thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; thd->proc_info="copy to tmp table"; - next_insert_id=thd->next_insert_id; // Remember for logging copied=deleted=0; if (new_table && !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER)) { @@ -5794,7 +5792,6 @@ bool mysql_alter_table(THD *thd,char *ne error=copy_data_between_tables(table, new_table, create_list, ignore, order_num, order, &copied, &deleted); } - thd->last_insert_id=next_insert_id; // Needed for correct log thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* If we did not need to copy, we might still need to add/drop indexes. */ @@ -6223,6 +6220,7 @@ copy_data_between_tables(TABLE *from,TAB ha_rows examined_rows; bool auto_increment_field_copied= 0; ulong save_sql_mode; + ulonglong prev_insert_id; DBUG_ENTER("copy_data_between_tables"); /* @@ -6328,6 +6326,7 @@ copy_data_between_tables(TABLE *from,TAB { copy_ptr->do_copy(copy_ptr); } + prev_insert_id= to->file->next_insert_id; if ((error=to->file->ha_write_row((byte*) to->record[0]))) { if (!ignore || @@ -6351,7 +6350,7 @@ copy_data_between_tables(TABLE *from,TAB to->file->print_error(error,MYF(0)); break; } - to->file->restore_auto_increment(); + to->file->restore_auto_increment(prev_insert_id); delete_count++; } else @@ -6385,6 +6384,7 @@ copy_data_between_tables(TABLE *from,TAB free_io_cache(from); *copied= found_count; *deleted=delete_count; + to->file->ha_release_auto_increment(); if (to->file->ha_external_lock(thd,F_UNLCK)) error=1; DBUG_RETURN(error > 0 ? -1 : 0); --- 1.199/sql/sql_update.cc 2006-07-13 00:19:21 +04:00 +++ 1.200/sql/sql_update.cc 2006-07-13 00:19:21 +04:00 @@ -135,7 +135,8 @@ int mysql_update(THD *thd, SQL_SELECT *select; READ_RECORD info; SELECT_LEX *select_lex= &thd->lex->select_lex; - bool need_reopen; + bool need_reopen; + ulonglong id; DBUG_ENTER("mysql_update"); for ( ; ; ) @@ -676,6 +677,10 @@ int mysql_update(THD *thd, thd->lock=0; } + /* If LAST_INSERT_ID(X) was used, report X */ + id= thd->arg_of_last_insert_id_function ? + thd->first_successful_insert_id_in_prev_stmt : 0; + if (error < 0) { char buff[STRING_BUFFER_USUAL_SIZE]; @@ -683,8 +688,7 @@ int mysql_update(THD *thd, (ulong) thd->cuted_fields); thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; - send_ok(thd, (ulong) thd->row_count_func, - thd->insert_id_used ? thd->insert_id() : 0L,buff); + send_ok(thd, (ulong) thd->row_count_func, id, buff); DBUG_PRINT("info",("%d records updated",updated)); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ @@ -1634,6 +1638,7 @@ err2: bool multi_update::send_eof() { char buff[STRING_BUFFER_USUAL_SIZE]; + ulonglong id; thd->proc_info="updating reference tables"; /* Does updates for the last n - 1 tables, returns 0 if ok */ @@ -1686,12 +1691,12 @@ bool multi_update::send_eof() return TRUE; } - + id= thd->arg_of_last_insert_id_function ? + thd->first_successful_insert_id_in_prev_stmt : 0; sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->cuted_fields); thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; - ::send_ok(thd, (ulong) thd->row_count_func, - thd->insert_id_used ? thd->insert_id() : 0L,buff); + ::send_ok(thd, (ulong) thd->row_count_func, id, buff); return FALSE; } --- 1.230/sql/table.cc 2006-07-13 00:19:21 +04:00 +++ 1.231/sql/table.cc 2006-07-13 00:19:21 +04:00 @@ -3925,16 +3925,7 @@ void st_table::mark_auto_increment_colum void st_table::mark_columns_needed_for_delete() { if (triggers) - { - if (triggers->bodies[TRG_EVENT_DELETE][TRG_ACTION_BEFORE] || - triggers->bodies[TRG_EVENT_DELETE][TRG_ACTION_AFTER]) - { - /* TODO: optimize to only add columns used by trigger */ - use_all_columns(); - return; - } - } - + triggers->mark_fields_used(TRG_EVENT_DELETE); if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE) { Field **reg_field; @@ -3985,15 +3976,7 @@ void st_table::mark_columns_needed_for_u { DBUG_ENTER("mark_columns_needed_for_update"); if (triggers) - { - if (triggers->bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE] || - triggers->bodies[TRG_EVENT_UPDATE][TRG_ACTION_AFTER]) - { - /* TODO: optimize to only add columns used by trigger */ - use_all_columns(); - DBUG_VOID_RETURN; - } - } + triggers->mark_fields_used(TRG_EVENT_UPDATE); if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE) { /* Mark all used key columns for read */ @@ -4036,13 +4019,14 @@ void st_table::mark_columns_needed_for_i { if (triggers) { - if (triggers->bodies[TRG_EVENT_INSERT][TRG_ACTION_BEFORE] || - triggers->bodies[TRG_EVENT_INSERT][TRG_ACTION_AFTER]) - { - /* TODO: optimize to only add columns used by trigger */ - use_all_columns(); - return; - } + /* + We don't need to mark columns which are used by ON DELETE and + ON UPDATE triggers, which may be invoked in case of REPLACE or + INSERT ... ON DUPLICATE KEY UPDATE, since before doing actual + row replacement or update write_record() will mark all table + fields as used. + */ + triggers->mark_fields_used(TRG_EVENT_INSERT); } if (found_next_number_field) mark_auto_increment_column(); --- 1.59/sql/sql_trigger.cc 2006-07-13 00:19:21 +04:00 +++ 1.60/sql/sql_trigger.cc 2006-07-13 00:19:21 +04:00 @@ -733,7 +733,8 @@ bool Table_triggers_list::prepare_record QQ: it is supposed that it is ok to use this function for field cloning... */ - if (!(*old_fld= (*fld)->new_field(&table->mem_root, table))) + if (!(*old_fld= (*fld)->new_field(&table->mem_root, table, + table == (*fld)->table))) return 1; (*old_fld)->move_field_offset((my_ptrdiff_t)(table->record[1] - table->record[0])); --- 1.338/sql/ha_ndbcluster.cc 2006-07-13 00:19:21 +04:00 +++ 1.339/sql/ha_ndbcluster.cc 2006-07-13 00:19:21 +04:00 @@ -2473,9 +2473,7 @@ int ha_ndbcluster::write_row(byte *recor m_skip_auto_increment= FALSE; update_auto_increment(); - /* Ensure that handler is always called for auto_increment values */ - thd->next_insert_id= 0; - m_skip_auto_increment= !auto_increment_column_changed; + m_skip_auto_increment= (insert_id_for_cur_row == 0); } } @@ -4785,7 +4783,7 @@ int ha_ndbcluster::create(const char *na expect it to be there. */ if (!ndbcluster_create_event(ndb, m_table, event_name.c_ptr(), share, - share && do_event_op /* push warning */)) + share && do_event_op ? 2 : 1/* push warning */)) { if (ndb_extra_logging) sql_print_information("NDB Binlog: CREATE TABLE Event: %s", @@ -5179,7 +5177,7 @@ int ha_ndbcluster::rename_table(const ch const NDBTAB *ndbtab= ndbtab_g2.get_table(); if (!ndbcluster_create_event(ndb, ndbtab, event_name.c_ptr(), share, - share && ndb_binlog_running /* push warning */)) + share && ndb_binlog_running ? 2 : 1/* push warning */)) { if (ndb_extra_logging) sql_print_information("NDB Binlog: RENAME Event: %s", --- 1.61/sql/ha_partition.cc 2006-07-13 00:19:21 +04:00 +++ 1.62/sql/ha_partition.cc 2006-07-13 00:19:21 +04:00 @@ -5284,7 +5284,7 @@ int ha_partition::cmp_ref(const byte *re MODULE auto increment ****************************************************************************/ -void ha_partition::restore_auto_increment() +void ha_partition::restore_auto_increment(ulonglong) { DBUG_ENTER("ha_partition::restore_auto_increment"); --- 1.32/mysql-test/r/federated.result 2006-07-13 00:19:21 +04:00 +++ 1.33/mysql-test/r/federated.result 2006-07-13 00:19:21 +04:00 @@ -1558,6 +1558,8 @@ id 3 4 5 +DROP TABLE federated.t1; +DROP TABLE federated.t1; DROP TABLE IF EXISTS federated.bug_17377_table; CREATE TABLE federated.bug_17377_table ( `fld_cid` bigint(20) NOT NULL auto_increment, @@ -1630,6 +1632,92 @@ a b c 5 6 30 drop tables federated.t1, federated.t2; drop table federated.t1; +create table federated.t1 (i1 int, i2 int, i3 int); +create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)); +create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:SLAVE_PORT/federated/t1'; +create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:SLAVE_PORT/federated/t2'; +insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from federated.t1 order by i1; +i1 i2 i3 +1 5 10 +2 2 2 +3 7 12 +4 5 2 +9 10 15 +select * from federated.t2; +id c1 c2 +9 abc def +5 opq lmn +2 test t t test +update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from federated.t1 order by i1; +i1 i2 i3 +1 5 10 +2 15 2 +3 7 12 +4 5 2 +9 15 15 +select * from federated.t2 order by id; +id c1 c2 +2 test t ppc +5 opq lmn +9 abc ppc +delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id; +select * from federated.t1 order by i1; +i1 i2 i3 +2 15 2 +3 7 12 +9 15 15 +select * from federated.t2 order by id; +id c1 c2 +2 test t ppc +9 abc ppc +drop table federated.t1, federated.t2; +drop table federated.t1, federated.t2; +create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1)); +create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id)); +create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:SLAVE_PORT/federated/t1'; +create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:SLAVE_PORT/federated/t2'; +insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from federated.t1 order by i1; +i1 i2 i3 +1 5 10 +2 2 2 +3 7 12 +4 5 2 +9 10 15 +select * from federated.t2 order by id; +id c1 c2 +2 test t t test +5 opq lmn +9 abc def +update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from federated.t1 order by i1; +i1 i2 i3 +1 5 10 +2 15 2 +3 7 12 +4 5 2 +9 15 15 +select * from federated.t2 order by id; +id c1 c2 +2 test t ppc +5 opq lmn +9 abc ppc +delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id; +select * from federated.t1 order by i1; +i1 i2 i3 +2 15 2 +3 7 12 +9 15 15 +select * from federated.t2 order by id; +id c1 c2 +2 test t ppc +9 abc ppc +drop table federated.t1, federated.t2; +drop table federated.t1, federated.t2; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; --- 1.28/mysql-test/t/federated.test 2006-07-13 00:19:21 +04:00 +++ 1.29/mysql-test/t/federated.test 2006-07-13 00:19:21 +04:00 @@ -1256,6 +1256,10 @@ SELECT LAST_INSERT_ID(); INSERT INTO federated.t1 VALUES (); SELECT LAST_INSERT_ID(); SELECT * FROM federated.t1; +DROP TABLE federated.t1; + +connection slave; +DROP TABLE federated.t1; # # Bug#17377 Federated Engine returns wrong Data, always the rows @@ -1310,7 +1314,6 @@ select * from federated.t1 where fld_par DROP TABLE federated.t1; connection slave; DROP TABLE federated.bug_17377_table; -DROP TABLE federated.t1; # # Test multi updates and deletes without keys @@ -1405,4 +1408,56 @@ drop tables federated.t1, federated.t2; connection slave; drop table federated.t1; ---source include/federated_cleanup.inc +# +# BUG 19773 Crash when using multi-table updates, deletes +# with federated tables +# +connection slave; +create table federated.t1 (i1 int, i2 int, i3 int); +create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)); + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:$SLAVE_MYPORT/federated/t1'; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:$SLAVE_MYPORT/federated/t2'; +insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from federated.t1 order by i1; +select * from federated.t2; +update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from federated.t1 order by i1; +select * from federated.t2 order by id; +delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id; +select * from federated.t1 order by i1; +select * from federated.t2 order by id; +drop table federated.t1, federated.t2; +connection slave; +drop table federated.t1, federated.t2; + +# Test multi updates and deletes with keys +connection slave; +create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1)); +create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id)); + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:$SLAVE_MYPORT/federated/t1'; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED CONNECTION='mysql://root@stripped:$SLAVE_MYPORT/federated/t2'; +insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2); +insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test"); +select * from federated.t1 order by i1; +select * from federated.t2 order by id; +update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id; +select * from federated.t1 order by i1; +select * from federated.t2 order by id; +delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id; +select * from federated.t1 order by i1; +select * from federated.t2 order by id; +drop table federated.t1, federated.t2; + +connection slave; +drop table federated.t1, federated.t2; + +source include/federated_cleanup.inc;