diff options
author | unknown <monty@mashka.mysql.fi> | 2003-01-04 15:40:55 +0200 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2003-01-04 15:40:55 +0200 |
commit | 8ce6c9fc6c3091c43ab91980fe904ed5125ba597 (patch) | |
tree | 49da2620373e1b4c73d505405819d5d7097786bc /sql | |
parent | f67891c24422a223a50a2477883e587c520057ad (diff) | |
parent | e229fe9801cc9fb7e3783cf708bc7cb695606c64 (diff) | |
download | mariadb-git-8ce6c9fc6c3091c43ab91980fe904ed5125ba597.tar.gz |
merge
BitKeeper/etc/logging_ok:
auto-union
include/mysql.h:
Auto merged
libmysql/libmysql.c:
Auto merged
mysql-test/r/multi_update.result:
Auto merged
mysql-test/t/multi_update.test:
Auto merged
mysys/Makefile.am:
Auto merged
sql/field.cc:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_func.h:
Auto merged
sql/log_event.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/share/english/errmsg.txt:
Auto merged
sql/share/italian/errmsg.txt:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_udf.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 6 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 30 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 33 | ||||
-rw-r--r-- | sql/ha_myisammrg.cc | 11 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 3 | ||||
-rw-r--r-- | sql/item_create.cc | 14 | ||||
-rw-r--r-- | sql/item_create.h | 1 | ||||
-rw-r--r-- | sql/item_func.cc | 7 | ||||
-rw-r--r-- | sql/item_func.h | 7 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/log.cc | 28 | ||||
-rw-r--r-- | sql/log_event.cc | 23 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/mysqld.cc | 27 | ||||
-rw-r--r-- | sql/net_serv.cc | 48 | ||||
-rw-r--r-- | sql/repl_failsafe.cc | 2 | ||||
-rw-r--r-- | sql/set_var.cc | 69 | ||||
-rw-r--r-- | sql/set_var.h | 18 | ||||
-rw-r--r-- | sql/share/english/errmsg.txt | 4 | ||||
-rw-r--r-- | sql/share/italian/errmsg.txt | 38 | ||||
-rw-r--r-- | sql/slave.cc | 9 | ||||
-rw-r--r-- | sql/slave.h | 10 | ||||
-rw-r--r-- | sql/sql_acl.cc | 2 | ||||
-rw-r--r-- | sql/sql_analyse.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 4 | ||||
-rw-r--r-- | sql/sql_db.cc | 2 | ||||
-rw-r--r-- | sql/sql_insert.cc | 21 | ||||
-rw-r--r-- | sql/sql_load.cc | 15 | ||||
-rw-r--r-- | sql/sql_parse.cc | 90 | ||||
-rw-r--r-- | sql/sql_repl.cc | 75 | ||||
-rw-r--r-- | sql/sql_select.cc | 39 | ||||
-rw-r--r-- | sql/sql_show.cc | 12 | ||||
-rw-r--r-- | sql/sql_table.cc | 66 | ||||
-rw-r--r-- | sql/sql_update.cc | 7 | ||||
-rw-r--r-- | sql/structs.h | 2 |
35 files changed, 514 insertions, 219 deletions
diff --git a/sql/field.cc b/sql/field.cc index 0813c1fc6cc..5f99171b04a 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4592,9 +4592,11 @@ void Field_blob::get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetyp if ((uint32) length > blob_length) { -#ifdef HAVE_purify + /* + Must clear this as we do a memcmp in opt_range.cc to detect + identical keys + */ bzero(buff+2+blob_length, (length-blob_length)); -#endif length=(uint) blob_length; } int2store(buff,length); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 8f933085066..bab5152725f 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -225,10 +225,14 @@ convert_error_code_to_mysql( return(HA_ERR_ROW_IS_REFERENCED); - } else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) { + } else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) { return(HA_ERR_CANNOT_ADD_FOREIGN); + } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { + + return(HA_ERR_WRONG_TABLE_DEF); + } else if (error == (int) DB_OUT_OF_FILE_SPACE) { return(HA_ERR_RECORD_FILE_FULL); @@ -1233,7 +1237,14 @@ ha_innobase::open( if (primary_key != MAX_KEY) { fprintf(stderr, "InnoDB: Error: table %s has no primary key in InnoDB\n" - "InnoDB: data dictionary, but has one in MySQL!\n", name); + "InnoDB: data dictionary, but has one in MySQL!\n" + "InnoDB: If you created the table with a MySQL\n" + "InnoDB: version < 3.23.54 and did not define a primary\n" + "InnoDB: key, but defined a unique key with all non-NULL\n" + "InnoDB: columns, then MySQL internally treats that key\n" + "InnoDB: as the primary key. You can fix this error by\n" + "InnoDB: dump + DROP + CREATE + reimport of the table.\n", + name); } ((row_prebuilt_t*)innobase_prebuilt) @@ -1898,12 +1909,9 @@ ha_innobase::write_row( the counter here. */ skip_auto_inc_decr = FALSE; - - if (error == DB_DUPLICATE_KEY) { - ut_a(user_thd->query); - dict_accept(user_thd->query, "REPLACE", - &skip_auto_inc_decr); - } + if (error == DB_DUPLICATE_KEY && + user_thd->lex.sql_command == SQLCOM_REPLACE) + skip_auto_inc_decr= TRUE; if (!skip_auto_inc_decr && incremented_auto_inc_counter && prebuilt->trx->auto_inc_lock) { @@ -3803,8 +3811,8 @@ innobase_map_isolation_level( enum_tx_isolation iso) /* in: MySQL isolation level code */ { switch(iso) { - case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED); case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ); + case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED); case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE); case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED); default: ut_a(0); return(0); @@ -3859,11 +3867,9 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use++; prebuilt->mysql_has_locked = TRUE; - if (thd->variables.tx_isolation != ISO_REPEATABLE_READ) { - trx->isolation_level = innobase_map_isolation_level( + trx->isolation_level = innobase_map_isolation_level( (enum_tx_isolation) thd->variables.tx_isolation); - } if (trx->isolation_level == TRX_ISO_SERIALIZABLE && prebuilt->select_lock_type == LOCK_NONE) { diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 67fddf34d5c..84dec41ea07 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -637,7 +637,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) the following 'if', thought conceptually wrong, is a useful optimization nevertheless. */ - if (file->state != &file->s->state.state); + if (file->state != &file->s->state.state) file->s->state.state = *file->state; if (file->s->base.auto_key) update_auto_increment_key(¶m, file, 1); @@ -691,12 +691,22 @@ void ha_myisam::deactivate_non_unique_index(ha_rows rows) mi_extra(file, HA_EXTRA_NO_KEYS, 0); else { - /* Only disable old index if the table was empty */ - if (file->state->records == 0) + /* + Only disable old index if the table was empty and we are inserting + a lot of rows. + We should not do this for only a few rows as this is slower and + we don't want to update the key statistics based of only a few rows. + */ + if (file->state->records == 0 && + (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)) mi_disable_non_unique_index(file,rows); - ha_myisam::extra_opt(HA_EXTRA_BULK_INSERT_BEGIN, - current_thd->variables.bulk_insert_buff_size); - table->bulk_insert= 1; + else + { + mi_init_bulk_insert(file, + current_thd->variables.bulk_insert_buff_size, + rows); + table->bulk_insert= 1; + } } } enable_activate_all_index=1; @@ -713,7 +723,7 @@ bool ha_myisam::activate_all_index(THD *thd) MYISAM_SHARE* share = file->s; DBUG_ENTER("activate_all_index"); - mi_extra(file, HA_EXTRA_BULK_INSERT_END, 0); + mi_end_bulk_insert(file); table->bulk_insert= 0; if (enable_activate_all_index && share->state.key_map != set_bits(ulonglong, share->base.keys)) @@ -954,13 +964,11 @@ int ha_myisam::extra(enum ha_extra_function operation) } -/* To be used with WRITE_CACHE, EXTRA_CACHE and BULK_INSERT_BEGIN */ +/* To be used with WRITE_CACHE and EXTRA_CACHE */ int ha_myisam::extra_opt(enum ha_extra_function operation, ulong cache_size) { - if ((specialflag & SPECIAL_SAFE_MODE) & - (operation == HA_EXTRA_WRITE_CACHE || - operation == HA_EXTRA_BULK_INSERT_BEGIN)) + if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE) return 0; return mi_extra(file, operation, (void*) &cache_size); } @@ -1224,8 +1232,7 @@ longlong ha_myisam::get_auto_increment() } if (table->bulk_insert) - mi_extra(file, HA_EXTRA_BULK_INSERT_FLUSH, - (void*) &table->next_number_index); + mi_flush_bulk_insert(file, table->next_number_index); longlong nr; int error; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 4398aaecf4d..3bd812821f6 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -239,6 +239,13 @@ void ha_myisammrg::info(uint flag) #else ref_length=4; // Can't be > than my_off_t #endif + if (flag & HA_STATUS_CONST) + { + if (table->key_parts) + memcpy((char*) table->key_info[0].rec_per_key, + (char*) info.rec_per_key, + sizeof(table->key_info[0].rec_per_key)*table->key_parts); + } } @@ -257,9 +264,7 @@ int ha_myisammrg::extra(enum ha_extra_function operation) int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size) { - if ((specialflag & SPECIAL_SAFE_MODE) & - (operation == HA_EXTRA_WRITE_CACHE || - operation == HA_EXTRA_BULK_INSERT_BEGIN)) + if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE) return 0; return myrg_extra(file, operation, (void*) &cache_size); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 94423642fa5..3d65c05b9cf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -868,8 +868,9 @@ String *Item_func_case::val_str(String *str) null_value=1; return 0; } + null_value= 0; if (!(res=item->val_str(str))) - null_value=1; + null_value= 1; return res; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 259427af901..0dba7f6e3ae 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -303,6 +303,18 @@ Item *create_func_pow(Item* a, Item *b) return new Item_func_pow(a,b); } +Item *create_func_current_user() +{ + THD *thd=current_thd; + char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + uint length; + + length= (uint) (strxmov(buff, thd->priv_user, "@", thd->host_or_ip, NullS) - + buff); + return new Item_string("CURRENT_USER()", thd->memdup(buff, length), length, + default_charset_info); +} + Item *create_func_quarter(Item* a) { return new Item_func_quarter(a); @@ -406,7 +418,7 @@ Item *create_func_ucase(Item* a) Item *create_func_version(void) { - return new Item_string(NullS,server_version, + return new Item_string("VERSION()",server_version, (uint) strlen(server_version), default_charset_info); } diff --git a/sql/item_create.h b/sql/item_create.h index 937ea782273..97386ca9b0b 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -71,6 +71,7 @@ Item *create_func_period_add(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b); Item *create_func_pi(void); Item *create_func_pow(Item* a, Item *b); +Item *create_func_current_user(void); Item *create_func_quarter(Item* a); Item *create_func_radians(Item *a); Item *create_func_release_lock(Item* a); diff --git a/sql/item_func.cc b/sql/item_func.cc index f0c956b873a..dcf4638c48a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2179,11 +2179,14 @@ void Item_func_get_user_var::fix_length_and_dec() maybe_null=1; decimals=NOT_FIXED_DEC; max_length=MAX_BLOB_WIDTH; - if ((var_entry= get_variable(&thd->user_vars, name, 0))) - const_var_flag= thd->query_id != var_entry->update_query_id; + var_entry= get_variable(&thd->user_vars, name, 0); } +bool Item_func_get_user_var::const_item() const +{ return var_entry && current_thd->query_id != var_entry->update_query_id; } + + enum Item_result Item_func_get_user_var::result_type() const { user_var_entry *entry; diff --git a/sql/item_func.h b/sql/item_func.h index 522b954b7b5..bf64412cab3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -934,11 +934,10 @@ class Item_func_get_user_var :public Item_func { LEX_STRING name; user_var_entry *var_entry; - bool const_var_flag; public: Item_func_get_user_var(LEX_STRING a): - Item_func(), name(a), const_var_flag(1) {} + Item_func(), name(a) {} user_var_entry *get_entry(); double val(); longlong val_int(); @@ -952,9 +951,9 @@ public: */ enum_field_types field_type() const { return MYSQL_TYPE_STRING; } const char *func_name() const { return "get_user_var"; } - bool const_item() const { return const_var_flag; } + bool const_item() const; table_map used_tables() const - { return const_var_flag ? 0 : RAND_TABLE_BIT; } + { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; }; diff --git a/sql/lex.h b/sql/lex.h index 78255d477fa..2ddc540991b 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -426,7 +426,7 @@ static SYMBOL sql_functions[] = { { "CAST", SYM(CAST_SYM),0,0}, { "CEIL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)}, { "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)}, - { "CURRENT_USER", SYM(USER),0,0}, + { "CURRENT_USER", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_current_user)}, { "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)}, { "CENTROID", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_centroid)}, { "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)}, diff --git a/sql/log.cc b/sql/log.cc index e21963022d9..5dcb5857026 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -662,7 +662,12 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) rli->linfo.log_file_name); goto err; } + /* + Reset position to current log. This involves setting both of the + position variables: + */ rli->relay_log_pos = BIN_LOG_HEADER_SIZE; + rli->pending = 0; strmake(rli->relay_log_name,rli->linfo.log_file_name, sizeof(rli->relay_log_name)-1); @@ -1121,8 +1126,20 @@ bool MYSQL_LOG::write(Log_event* event_info) if (file == &log_file) { - error = ha_report_binlog_offset_and_commit(thd, log_file_name, + /* + LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog + chunks also before it is successfully completed. We only report + the binlog write and do the commit inside the transactional table + handler if the log event type is appropriate. + */ + + if (event_info->get_type_code() == QUERY_EVENT + || event_info->get_type_code() == EXEC_LOAD_EVENT) + { + error = ha_report_binlog_offset_and_commit(thd, log_file_name, file->pos_in_file); + } + should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); } @@ -1165,7 +1182,7 @@ uint MYSQL_LOG::next_file_id() NOTE - We only come here if there is something in the cache. - - The thing in the cache is always a complete transcation + - The thing in the cache is always a complete transaction - 'cache' needs to be reinitialized after this functions returns. IMPLEMENTATION @@ -1233,6 +1250,13 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) log_file.pos_in_file))) goto err; signal_update(); + if (my_b_tell(&log_file) >= (my_off_t) max_binlog_size) + { + pthread_mutex_lock(&LOCK_index); + new_file(0); // inside mutex + pthread_mutex_unlock(&LOCK_index); + } + } VOID(pthread_mutex_unlock(&LOCK_log)); DBUG_RETURN(0); diff --git a/sql/log_event.cc b/sql/log_event.cc index a01b1ee6170..8f98fa511a0 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -296,9 +296,13 @@ int Log_event::exec_event(struct st_relay_log_info* rli) { if (rli) // QQ When is this not true ? { - rli->inc_pos(get_event_len(),log_pos); - DBUG_ASSERT(rli->sql_thd != 0); - flush_relay_log_info(rli); + if (rli->inside_transaction) + rli->inc_pending(get_event_len()); + else + { + rli->inc_pos(get_event_len(),log_pos); + flush_relay_log_info(rli); + } } return 0; } @@ -865,6 +869,19 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) mysql_log.write(thd,COM_QUERY,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); mysql_parse(thd, thd->query, q_len); + + /* + Set a flag if we are inside an transaction so that we can restart + the transaction from the start if we are killed + + This will only be done if we are supporting transactional tables + in the slave. + */ + if (!strcmp(thd->query,"BEGIN")) + rli->inside_transaction= opt_using_transactions; + else if (!strcmp(thd->query,"COMMIT")) + rli->inside_transaction=0; + DBUG_PRINT("info",("expected_error: %d last_errno: %d", expected_error, thd->net.last_errno)); if ((expected_error != (actual_error= thd->net.last_errno)) && diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4d819ef6ae7..fa9514c63b7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -323,11 +323,12 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); -int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists); +int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, + my_bool drop_temporary); int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, - bool log_query); + bool drop_temporary, bool log_query); int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, - bool if_exists, + bool if_exists, bool drop_temporary, bool log_query); int quick_rm_table(enum db_type base,const char *db, const char *table_name); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b607bcdb3a1..c2dfc9d1935 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -206,7 +206,7 @@ static char **opt_argv; #else #define MYSQL_SERVER_SUFFIX "" #endif /* __NT__ */ -#endif +#endif /* __WIN__ */ #ifdef HAVE_BERKELEY_DB SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_YES; @@ -247,6 +247,12 @@ SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO; const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; bool opt_large_files= sizeof(my_off_t) > 4; +#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) +#define GET_HA_ROWS GET_ULL +#else +#define GET_HA_ROWS GET_ULONG +#endif + /* Variables to store startup options @@ -3793,8 +3799,13 @@ struct my_option my_long_options[] = {"lower_case_table_names", OPT_LOWER_CASE_TABLE_NAMES, "If set to 1 table names are stored in lowercase on disk and table names will be case-insensitive.", (gptr*) &lower_case_table_names, - (gptr*) &lower_case_table_names, 0, - GET_BOOL, NO_ARG, IF_WIN(1,0), 0, 1, 0, 1, 0}, + (gptr*) &lower_case_table_names, 0, GET_BOOL, NO_ARG, +#ifdef FN_NO_CASE_SENCE + 1 +#else + 0 +#endif + , 0, 1, 0, 1, 0}, {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET, "Max packetlength to send/receive from to server.", (gptr*) &global_system_variables.max_allowed_packet, @@ -3833,7 +3844,7 @@ struct my_option my_long_options[] = {"max_join_size", OPT_MAX_JOIN_SIZE, "Joins that are probably going to read more than max_join_size records return an error.", (gptr*) &global_system_variables.max_join_size, - (gptr*) &max_system_variables.max_join_size, 0, GET_ULONG, REQUIRED_ARG, + (gptr*) &max_system_variables.max_join_size, 0, GET_HA_ROWS, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, {"max_prepared_statements", OPT_MAX_PREP_STMT, "Max number of prepared_statements for a thread", @@ -4234,12 +4245,12 @@ static void set_options(void) sizeof(mysql_real_data_home)-1); /* Set default values for some variables */ - global_system_variables.table_type=DB_TYPE_MYISAM; - global_system_variables.tx_isolation=ISO_REPEATABLE_READ; + global_system_variables.table_type= DB_TYPE_MYISAM; + global_system_variables.tx_isolation= ISO_REPEATABLE_READ; global_system_variables.select_limit= (ulonglong) HA_POS_ERROR; - max_system_variables.select_limit= (ulong) HA_POS_ERROR; + max_system_variables.select_limit= (ulonglong) HA_POS_ERROR; global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; - max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; #ifdef __WIN__ /* Allow Win32 users to move MySQL anywhere */ diff --git a/sql/net_serv.cc b/sql/net_serv.cc index d165125eb90..cd1238ff6d4 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -73,7 +73,7 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #include "thr_alarm.h" #define TEST_BLOCKING 8 -#define MAX_THREE_BYTES 255L*255L*255L +#define MAX_THREE_BYTES (256L*256L*256L-1) static my_bool net_write_buff(NET *net,const char *packet,ulong len); @@ -312,6 +312,7 @@ net_write_command(NET *net,uchar command, /* Caching the data in a local buffer before sending it. One can force the buffer to be flushed with 'net_flush'. + */ static my_bool @@ -319,15 +320,24 @@ net_write_buff(NET *net,const char *packet,ulong len) { ulong left_length=(ulong) (net->buff_end - net->write_pos); - while (len > left_length) + if (len > left_length) { memcpy((char*) net->write_pos,packet,left_length); if (net_real_write(net,(char*) net->buff,net->max_packet)) return 1; net->write_pos=net->buff; packet+=left_length; - len-=left_length; - left_length=net->max_packet; + len-= left_length; + left_length= net->max_packet; + + /* Send out rest of the blocks as full sized blocks */ + while (len > left_length) + { + if (net_real_write(net, packet, left_length)) + return 1; + packet+= left_length; + len-= left_length; + } } memcpy((char*) net->write_pos,packet,len); net->write_pos+=len; @@ -500,6 +510,7 @@ static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed) ALARM alarm_buff; uint retry_count=0; my_bool old_mode; + uint32 old=remain; if (!thr_alarm_in_use(&alarmed)) { @@ -521,6 +532,12 @@ static void my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed) return; } remain -= (uint32) length; + if (!remain && old==MAX_THREE_BYTES && + (length=vio_read(net->vio,(char*) net->buff,NET_HEADER_SIZE))) + { + old=remain= uint3korr(net->buff); + net->pkt_nr++; + } statistic_add(bytes_received,length,&LOCK_bytes_received); } } @@ -667,7 +684,10 @@ my_real_read(NET *net, ulong *complen) #ifdef HAVE_COMPRESS if (net->compress) { - /* complen is > 0 if package is really compressed */ + /* + If the packet is compressed then complen > 0 and contains the + number of bytes in the uncompressed packet + */ *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE])); } #endif @@ -681,11 +701,19 @@ my_real_read(NET *net, ulong *complen) { if (net_realloc(net,helping)) { +#ifdef MYSQL_SERVER #ifndef NO_ALARM - if (i == 1) - my_net_skip_rest(net, (uint32) len, &alarmed); + if (net->compress) + { + len= packet_error; + goto end; + } + my_net_skip_rest(net, (uint32) len, &alarmed); + len=0; +#endif +#else + len= packet_error; /* Return error */ #endif - len= packet_error; /* Return error */ goto end; } } @@ -738,7 +766,7 @@ my_net_read(NET *net) { net->where_b += len; total_length += len; - len = my_real_read (net,&complen); + len = my_real_read(net,&complen); } while (len == MAX_THREE_BYTES); if (len != packet_error) len+= total_length; @@ -766,7 +794,7 @@ my_net_read(NET *net) } else { - /* reuse buffer, as there is noting in it that we need */ + /* reuse buffer, as there is nothing in it that we need */ buf_length=start_of_packet=first_packet_offset=0; } for (;;) diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 16b2eedd3b2..597bcff58f2 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -82,7 +82,7 @@ static int init_failsafe_rpl_thread(THD* thd) #endif thd->mem_root.free=thd->mem_root.used=0; - if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR) + if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; thd->proc_info="Thread initialized"; diff --git a/sql/set_var.cc b/sql/set_var.cc index c7dfb63a86f..a067bab01d7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -158,11 +158,11 @@ sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", &SV::max_heap_table_size); sys_var_thd_ulong sys_pseudo_thread_id("pseudo_thread_id", &SV::pseudo_thread_id); -sys_var_thd_ulonglong sys_max_join_size("max_join_size", +sys_var_thd_ha_rows sys_max_join_size("max_join_size", &SV::max_join_size, fix_max_join_size); #ifndef TO_BE_DELETED /* Alias for max_join_size */ -sys_var_thd_ulonglong sys_sql_max_join_size("sql_max_join_size", +sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size", &SV::max_join_size, fix_max_join_size); #endif @@ -284,7 +284,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", /* Local state variables */ -static sys_var_thd_ulonglong sys_select_limit("sql_select_limit", +static sys_var_thd_ha_rows sys_select_limit("sql_select_limit", &SV::select_limit); static sys_var_timestamp sys_timestamp("timestamp"); static sys_var_last_insert_id sys_last_insert_id("last_insert_id"); @@ -606,7 +606,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type) { if (type != OPT_GLOBAL) { - if (thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) + if (thd->variables.max_join_size == HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; else thd->options&= ~OPTION_BIG_SELECTS; @@ -753,12 +753,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) if (option_limits) tmp= (ulong) getopt_ull_limit_value(tmp, option_limits); if (var->type == OPT_GLOBAL) - { - /* Lock is needed to make things safe on 32 bit systems */ - pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= (ulong) tmp; - pthread_mutex_unlock(&LOCK_global_system_variables); - } else thd->variables.*offset= (ulong) tmp; return 0; @@ -785,10 +780,60 @@ byte *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type) } +bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) +{ + ulonglong tmp= var->value->val_int(); + + /* Don't use bigger value than given with --maximum-variable-name=.. */ + if ((ha_rows) tmp > max_system_variables.*offset) + tmp= max_system_variables.*offset; + + if (option_limits) + tmp= (ha_rows) getopt_ull_limit_value(tmp, option_limits); + if (var->type == OPT_GLOBAL) + { + /* Lock is needed to make things safe on 32 bit systems */ + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.*offset= (ha_rows) tmp; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.*offset= (ha_rows) tmp; + return 0; +} + + +void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + { + /* We will not come here if option_limits is not set */ + pthread_mutex_lock(&LOCK_global_system_variables); + global_system_variables.*offset= (ha_rows) option_limits->def_value; + pthread_mutex_unlock(&LOCK_global_system_variables); + } + else + thd->variables.*offset= global_system_variables.*offset; +} + + +byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + return (byte*) &(global_system_variables.*offset); + return (byte*) &(thd->variables.*offset); +} + + bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) { if (var->type == OPT_GLOBAL) + { + /* Lock is needed to make things safe on 32 bit systems */ + pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= var->value->val_int(); + pthread_mutex_unlock(&LOCK_global_system_variables); + } else thd->variables.*offset= var->value->val_int(); return 0; @@ -798,7 +843,11 @@ bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) + { + pthread_mutex_lock(&LOCK_global_system_variables); global_system_variables.*offset= (ulonglong) option_limits->def_value; + pthread_mutex_unlock(&LOCK_global_system_variables); + } else thd->variables.*offset= global_system_variables.*offset; } @@ -905,6 +954,8 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type)); case SHOW_LONGLONG: return new Item_int(*(longlong*) value_ptr(thd, var_type)); + case SHOW_HA_ROWS: + return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type)); case SHOW_MY_BOOL: return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type),1); case SHOW_CHAR: diff --git a/sql/set_var.h b/sql/set_var.h index f479cbad042..6f257e1ace3 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -212,6 +212,24 @@ public: }; +class sys_var_thd_ha_rows :public sys_var_thd +{ +public: + ha_rows SV::*offset; + sys_var_thd_ha_rows(const char *name_arg, ha_rows SV::*offset_arg) + :sys_var_thd(name_arg), offset(offset_arg) + {} + sys_var_thd_ha_rows(const char *name_arg, ha_rows SV::*offset_arg, + sys_after_update_func func) + :sys_var_thd(name_arg,func), offset(offset_arg) + {} + bool update(THD *thd, set_var *var); + void set_default(THD *thd, enum_var_type type); + SHOW_TYPE type() { return SHOW_HA_ROWS; } + byte *value_ptr(THD *thd, enum_var_type type); +}; + + class sys_var_thd_ulonglong :public sys_var_thd { public: diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index d235f8f49a5..465992e63b2 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -217,8 +217,8 @@ "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", -"Cannot add a child row: a foreign key constraint fails", -"Cannot delete a parent row: a foreign key constraint fails", +"Cannot add or update a child row: a foreign key constraint fails", +"Cannot delete or update a parent row: a foreign key constraint fails", "Error connecting to master: %-.128s", "Error running query on master: %-.128s", "Error when executing command %s: %-.128s", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 56b3018e3a6..451ad3e058b 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -219,25 +219,25 @@ "Impossibile aggiungere il vincolo di integrita' referenziale (foreign key constraint)", "Impossibile aggiungere la riga: un vincolo d'integrita' referenziale non e' soddisfatto", "Impossibile cancellare la riga: un vincolo d'integrita' referenziale non e' soddisfatto", -"Error connecting to master: %-.128s", -"Error running query on master: %-.128s", -"Error when executing command %s: %-.128s", -"Wrong usage of %s and %s", -"The used SELECT statements have a different number of columns", -"Can't execute the query because you have a conflicting read lock", -"Mixing of transactional and non-transactional tables is disabled", -"Option '%s' used twice in statement", -"User '%-.64s' has exceeded the '%s' resource (current value: %ld)", -"Access denied. You need the %-.128s privilege for this operation", -"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL", -"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL", -"Variable '%-.64s' doesn't have a default value", -"Variable '%-.64s' can't be set to the value of '%-.64s'", -"Wrong argument type to variable '%-.64s'", -"Variable '%-.64s' can only be set, not read", -"Wrong usage/placement of '%s'", -"This version of MySQL doesn't yet support '%s'", -"Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Errore durante la connessione al master: %-.128s", +"Errore eseguendo una query sul master: %-.128s", +"Errore durante l'esecuzione del comando %s: %-.128s", +"Uso errato di %s e %s", +"La SELECT utilizzata ha un numero di colonne differente", +"Impossibile eseguire la query perche' c'e' un conflitto con in lock di lettura", +"E' disabilitata la possibilita' di mischiare tabelle transazionali e non-transazionali", +"L'opzione '%s' e' stata usata due volte nel comando", +"L'utente '%-.64s' ha ecceduto la risorsa '%s' (valore corrente: %ld)", +"Accesso non consentito. Serve il privilegio %-.128s per questa operazione", +"La variabile '%-.64s' e' una variabile locale ( LOCAL ) e non puo' essere cambiata usando SET GLOBAL", +"La variabile '%-.64s' e' una variabile globale ( GLOBAL ) e deve essere cambiata usando SET GLOBAL", +"La variabile '%-.64s' non ha un valore di default", +"Alla variabile '%-.64s' non puo' essere assegato il valore '%-.64s'", +"Tipo di valore errato per la variabile '%-.64s'", +"Alla variabile '%-.64s' e' di sola scrittura quindi puo' essere solo assegnato un valore, non letto", +"Uso/posizione di '%s' sbagliato", +"Questa versione di MySQL non supporta ancora '%s'", +"Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario", "Wrong foreign key definition for '%-.64s': %s", "Key reference and table reference doesn't match", "Cardinality error (more/less than %d columns)", diff --git a/sql/slave.cc b/sql/slave.cc index 7d3ec8d3dce..342a35b8821 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1747,7 +1747,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals)); #endif - if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR) + if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; if (thd_type == SLAVE_THD_SQL) @@ -2965,7 +2965,12 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg) if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name, errmsg)) <0) DBUG_RETURN(0); - my_b_seek(cur_log,rli->relay_log_pos); + /* + We want to start exactly where we was before: + relay_log_pos Current log pos + pending Number of bytes already processed from the event + */ + my_b_seek(cur_log,rli->relay_log_pos + rli->pending); DBUG_RETURN(cur_log); } diff --git a/sql/slave.h b/sql/slave.h index 2c750e415bc..91eedd60c7c 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -186,11 +186,13 @@ typedef struct st_relay_log_info volatile bool abort_slave, slave_running; bool log_pos_current; bool skip_log_purge; - + bool inside_transaction; + st_relay_log_info() - :info_fd(-1),cur_log_fd(-1), cur_log_old_open_count(0), abort_pos_wait(0), - slave_run_id(0), inited(0), abort_slave(0), slave_running(0), - log_pos_current(0), skip_log_purge(0) + :info_fd(-1),cur_log_fd(-1), cur_log_old_open_count(0), abort_pos_wait(0), + slave_run_id(0), inited(0), abort_slave(0), slave_running(0), + log_pos_current(0), skip_log_purge(0), + inside_transaction(0) /* the default is autocommit=1 */ { relay_log_name[0] = master_log_name[0] = 0; bzero(&info_file,sizeof(info_file)); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 310ac16e927..6148df13902 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1936,7 +1936,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ulong rights, ulong col_rights, bool revoke_grant) { - char grantor[HOSTNAME_LENGTH+1+USERNAME_LENGTH]; + char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; int old_row_exists = 1; int error=0; ulong store_table_rights, store_col_rights; diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index c1d49fdab51..a424d877919 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -403,7 +403,6 @@ void field_real::add() length= my_sprintf(buff, (buff, "%-.*f", (int) decs, num)); #endif - // We never need to check further than this end = buff + length - 1 - decs + max_notzero_dec_len; diff --git a/sql/sql_class.h b/sql/sql_class.h index ab9230e5f01..a053db72e64 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -344,8 +344,8 @@ struct system_variables { ulonglong myisam_max_extra_sort_file_size; ulonglong myisam_max_sort_file_size; - ulonglong select_limit; - ulonglong max_join_size; + ha_rows select_limit; + ha_rows max_join_size; ulong bulk_insert_buff_size; ulong join_buff_size; ulong long_query_time; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 311bf29aee7..7ff4caf356c 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -468,7 +468,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, my_dirend(dirp); if (thd->killed || - (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 1))) + (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) DBUG_RETURN(-1); /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f45e09cf0bf..e76e982adea 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -109,7 +109,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, int error; bool log_on= ((thd->options & OPTION_UPDATE_LOG) || !(thd->master_access & SUPER_ACL)); - bool transactional_table, log_delayed, bulk_insert=0; + bool transactional_table, log_delayed, bulk_insert; uint value_count; ulong counter = 1; ulonglong id; @@ -217,21 +217,17 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, thd->proc_info="update"; if (duplic != DUP_ERROR) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - if ((bulk_insert= (values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT && - lock_type != TL_WRITE_DELAYED && - !(specialflag & SPECIAL_SAFE_MODE)))) + if ((lock_type != TL_WRITE_DELAYED && !(specialflag & SPECIAL_SAFE_MODE)) && + values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT) { table->file->extra_opt(HA_EXTRA_WRITE_CACHE, min(thd->variables.read_buff_size, table->avg_row_length*values_list.elements)); - if (thd->variables.bulk_insert_buff_size) - table->file->extra_opt(HA_EXTRA_BULK_INSERT_BEGIN, - min(thd->variables.bulk_insert_buff_size, - (table->total_key_length + - table->keys * TREE_ELEMENT_EXTRA_SIZE)* - values_list.elements)); - table->bulk_insert= 1; + table->file->deactivate_non_unique_index(values_list.elements); + bulk_insert=1; } + else + bulk_insert=0; while ((values= its++)) { @@ -309,7 +305,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, error=1; } } - if (table->file->extra(HA_EXTRA_BULK_INSERT_END)) + if (table->file->activate_all_index(thd)) { if (!error) { @@ -317,7 +313,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, error=1; } } - table->bulk_insert= 0; } if (id && values_list.elements != 1) thd->insert_id(id); // For update log diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 00450a3b86c..96ff33774ac 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -269,11 +269,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->time_stamp=save_time_stamp; table->next_number_field=0; - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } } if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ @@ -292,7 +287,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, mysql_bin_log.write(&d); } } - DBUG_RETURN(-1); // Error on read + error= -1; // Error on read + goto err; } sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted, info.records-info.copied,thd->cuted_fields); @@ -326,6 +322,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } if (transactional_table) error=ha_autocommit_or_rollback(thd,error); + +err: + if (thd->lock) + { + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; + } DBUG_RETURN(error); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e74c7e35328..b47ce194a57 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -516,6 +516,7 @@ check_connections(THD *thd) { vio_in_addr(net->vio,&thd->remote.sin_addr); thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + thd->host[strnlen(thd->host, HOSTNAME_LENGTH)]= 0; if (connect_errors > max_connect_errors) return(ER_HOST_IS_BLOCKED); } @@ -532,6 +533,7 @@ check_connections(THD *thd) thd->ip=0; bzero((char*) &thd->remote,sizeof(struct sockaddr)); } + /* Ensure that wrong hostnames doesn't cause buffer overflows */ vio_keepalive(net->vio, TRUE); ulong pkt_len=0; @@ -763,7 +765,7 @@ pthread_handler_decl(handle_one_connection,arg) goto end_thread; } - if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) + if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; if (thd->client_capabilities & CLIENT_COMPRESS) net->compress=1; // Use compression @@ -839,7 +841,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) #endif - if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) + if (thd->variables.max_join_size == HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; thd->proc_info=0; @@ -969,6 +971,12 @@ bool do_command(THD *thd) vio_description(net->vio) )); return TRUE; } + else if (!packet_length) + { + send_error(thd,net->last_errno,NullS); + net->error=0; + DBUG_RETURN(FALSE); + } else { packet=(char*) net->read_pos; @@ -1254,6 +1262,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } if (lower_case_table_names) my_casedn_str(files_charset_info, db); + if (check_access(thd,DROP_ACL,db,0,1)) + break; if (thd->locked_tables || thd->active_transaction()) { send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); @@ -1294,10 +1304,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (check_global_access(thd,RELOAD_ACL)) break; mysql_log.write(thd,command,NullS); - if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0)) - send_error(thd,0); - else - send_eof(thd); + /* error sending is deferred to reload_acl_and_cache */ + reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ; break; } case COM_SHUTDOWN: @@ -1638,7 +1646,9 @@ mysql_execute_command(THD *thd) { res= mysqld_show_warnings(thd, (ulong) ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) | - (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN))); + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) | + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR) + )); break; } case SQLCOM_SHOW_ERRORS: @@ -1880,6 +1890,24 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_SLAVE_STOP: + /* + If the client thread has locked tables, a deadlock is possible. + Assume that + - the client thread does LOCK TABLE t READ. + - then the master updates t. + - then the SQL slave thread wants to update t, + so it waits for the client thread because t is locked by it. + - then the client thread does SLAVE STOP. + SLAVE STOP waits for the SQL slave thread to terminate its + update t, which waits for the client thread because t is locked by it. + To prevent that, refuse SLAVE STOP if the + client thread has locked tables + */ + if (thd->locked_tables || thd->active_transaction()) + { + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); + break; + } { LOCK_ACTIVE_MI; stop_slave(thd,active_mi,1/* net report*/); @@ -2287,12 +2315,17 @@ mysql_execute_command(THD *thd) } case SQLCOM_DROP_TABLE: { - if (check_table_access(thd,DROP_ACL,tables)) - goto error; /* purecov: inspected */ - if (end_active_trans(thd)) - res= -1; - else - res = mysql_rm_table(thd,tables,lex->drop_if_exists); + if (!lex->drop_temporary) + { + if (check_table_access(thd,DROP_ACL,tables)) + goto error; /* purecov: inspected */ + if (end_active_trans(thd)) + { + res= -1; + break; + } + } + res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary); } break; case SQLCOM_DROP_INDEX: @@ -2673,10 +2706,8 @@ mysql_execute_command(THD *thd) case SQLCOM_RESET: if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables)) goto error; - if (reload_acl_and_cache(thd, lex->type, tables)) - send_error(thd,0); - else - send_ok(thd); + /* error sending is deferred to reload_acl_and_cache */ + reload_acl_and_cache(thd, lex->type, tables) ; break; case SQLCOM_KILL: kill_one_thread(thd,lex->thread_id); @@ -3690,10 +3721,15 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) b->natural_join=a; } + +/* + Reload/resets privileges and the different caches +*/ + bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) { bool result=0; - + bool error_already_sent=0; select_errors=0; /* Write if more errors */ if (options & REFRESH_GRANT) { @@ -3751,11 +3787,29 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables) { LOCK_ACTIVE_MI; if (reset_slave(thd, active_mi)) + { result=1; + /* + reset_slave() sends error itself. + If it didn't, one would either change reset_slave()'s prototype, to + pass *errorcode and *errmsg to it when it's called or + change reset_slave to use my_error() to register the error. + */ + error_already_sent=1; + } UNLOCK_ACTIVE_MI; } if (options & REFRESH_USER_RESOURCES) reset_mqh(thd,(LEX_USER *) NULL); + + if (thd && !error_already_sent) + { + if (result) + send_error(thd,0); + else + send_ok(thd); + } + return result; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 375a7478377..5bdc15c2bf0 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -696,20 +696,48 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) return 0; } + +/* + Remove all relay logs and start replication from the start + + SYNOPSIS + reset_slave() + thd Thread handler + mi Master info for the slave + + + NOTES + We don't send ok in this functions as this is called from + reload_acl_and_cache() which may have done other tasks, which may + have failed for which we want to send and error. + + RETURN + 0 ok + 1 error + In this case error is sent to the client with send_error() +*/ + + int reset_slave(THD *thd, MASTER_INFO* mi) { MY_STAT stat_area; char fname[FN_REFLEN]; - int restart_thread_mask = 0,error=0; + int thread_mask= 0, error= 0; + uint sql_errno=0; const char* errmsg=0; DBUG_ENTER("reset_slave"); lock_slave_threads(mi); - init_thread_mask(&restart_thread_mask,mi,0 /* not inverse */); - if ((error=terminate_slave_threads(mi,restart_thread_mask,1 /*skip lock*/)) - || (error=purge_relay_logs(&mi->rli, thd, - 1 /* just reset */, - &errmsg))) + init_thread_mask(&thread_mask,mi,0 /* not inverse */); + if (thread_mask) // We refuse if any slave thread is running + { + sql_errno= ER_SLAVE_MUST_STOP; + error=1; + goto err; + } + if ((error= purge_relay_logs(&mi->rli, thd, + 1 /* just reset */, + &errmsg))) goto err; end_master_info(mi); @@ -725,17 +753,15 @@ int reset_slave(THD *thd, MASTER_INFO* mi) error=1; goto err; } - if (restart_thread_mask) - error=start_slave_threads(0 /* mutex not needed */, - 1 /* wait for start*/, - mi,master_info_file,relay_log_info_file, - restart_thread_mask); - // TODO: fix error messages so they get to the client + err: unlock_slave_threads(mi); + if (thd && error) + send_error(thd, sql_errno, errmsg); DBUG_RETURN(error); } + void kill_zombie_dump_threads(uint32 slave_server_id) { pthread_mutex_lock(&LOCK_thread_count); @@ -767,23 +793,20 @@ void kill_zombie_dump_threads(uint32 slave_server_id) int change_master(THD* thd, MASTER_INFO* mi) { - int error=0,restart_thread_mask; + int thread_mask; const char* errmsg=0; bool need_relay_log_purge=1; DBUG_ENTER("change_master"); - // kill slave thread lock_slave_threads(mi); - init_thread_mask(&restart_thread_mask,mi,0 /*not inverse*/); - if (restart_thread_mask && - (error=terminate_slave_threads(mi, - restart_thread_mask, - 1 /*skip lock*/))) + init_thread_mask(&thread_mask,mi,0 /*not inverse*/); + if (thread_mask) // We refuse if any slave thread is running { - send_error(thd,error); + net_printf(thd,ER_SLAVE_MUST_STOP); unlock_slave_threads(mi); DBUG_RETURN(1); } + thd->proc_info = "changing master"; LEX_MASTER_INFO* lex_mi = &thd->lex.mi; // TODO: see if needs re-write @@ -852,6 +875,7 @@ int change_master(THD* thd, MASTER_INFO* mi) &errmsg)) { net_printf(thd, 0, "Failed purging old relay logs: %s",errmsg); + unlock_slave_threads(mi); DBUG_RETURN(1); } } @@ -882,18 +906,9 @@ int change_master(THD* thd, MASTER_INFO* mi) pthread_cond_broadcast(&mi->data_cond); pthread_mutex_unlock(&mi->rli.data_lock); - thd->proc_info = "starting slave"; - if (restart_thread_mask) - error=start_slave_threads(0 /* mutex not needed*/, - 1 /* wait for start*/, - mi,master_info_file,relay_log_info_file, - restart_thread_mask); unlock_slave_threads(mi); thd->proc_info = 0; - if (error) - send_error(thd,error); - else - send_ok(thd); + send_ok(thd); DBUG_RETURN(0); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ae45f96fbe8..b57e45a1a52 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1507,7 +1507,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, select->quick=0; if (records != HA_POS_ERROR) { - s->records=s->found_records=records; + s->found_records=records; s->read_time= (ha_rows) (s->quick ? s->quick->read_time : 0.0); } } @@ -4978,7 +4978,10 @@ join_read_const(JOIN_TAB *tab) empty_record(table); if (error != HA_ERR_KEY_NOT_FOUND) { - sql_print_error("read_const: Got error %d when reading table %s", + /* Locking reads can legally return also these errors, do not + print them to the .err log */ + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_const: Got error %d when reading table %s", error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5041,7 +5044,8 @@ join_read_always_key(JOIN_TAB *tab) { if (error != HA_ERR_KEY_NOT_FOUND) { - sql_print_error("read_const: Got error %d when reading table %s",error, + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_const: Got error %d when reading table %s",error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5070,7 +5074,8 @@ join_read_last_key(JOIN_TAB *tab) { if (error != HA_ERR_KEY_NOT_FOUND) { - sql_print_error("read_const: Got error %d when reading table %s",error, + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_const: Got error %d when reading table %s",error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5102,7 +5107,8 @@ join_read_next_same(READ_RECORD *info) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("read_next: Got error %d when reading table %s",error, + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_next: Got error %d when reading table %s",error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5124,7 +5130,8 @@ join_read_prev_same(READ_RECORD *info) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("read_next: Got error %d when reading table %s",error, + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_next: Got error %d when reading table %s",error, table->path); table->file->print_error(error,MYF(0)); error= 1; @@ -5195,7 +5202,8 @@ join_read_first(JOIN_TAB *tab) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) { - sql_print_error("read_first_with_key: Got error %d when reading table", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_first_with_key: Got error %d when reading table", error); table->file->print_error(error,MYF(0)); return 1; @@ -5214,7 +5222,9 @@ join_read_next(READ_RECORD *info) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("read_next_with_key: Got error %d when reading table %s", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error( + "read_next_with_key: Got error %d when reading table %s", error, info->table->path); info->file->print_error(error,MYF(0)); return 1; @@ -5246,7 +5256,8 @@ join_read_last(JOIN_TAB *tab) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("read_last_with_key: Got error %d when reading table", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("read_last_with_key: Got error %d when reading table", error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5265,7 +5276,9 @@ join_read_prev(READ_RECORD *info) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("read_prev_with_key: Got error %d when reading table: %s", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error( + "read_prev_with_key: Got error %d when reading table: %s", error,info->table->path); info->file->print_error(error,MYF(0)); return 1; @@ -5293,7 +5306,8 @@ join_ft_read_first(JOIN_TAB *tab) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("ft_read_first: Got error %d when reading table %s", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("ft_read_first: Got error %d when reading table %s", error, table->path); table->file->print_error(error,MYF(0)); return 1; @@ -5311,7 +5325,8 @@ join_ft_read_next(READ_RECORD *info) { if (error != HA_ERR_END_OF_FILE) { - sql_print_error("ft_read_next: Got error %d when reading table %s", + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("ft_read_next: Got error %d when reading table %s", error, info->table->path); info->file->print_error(error,MYF(0)); return 1; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ac9cc6b3002..c66764d673f 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1269,6 +1269,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) THD *tmp; while ((tmp=it++)) { + struct st_my_thread_var *mysys_var; if ((tmp->net.vio || tmp->system_thread) && (!user || (tmp->user && !strcmp(tmp->user,user)))) { @@ -1285,8 +1286,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); thd_info->command=(int) tmp->command; - if (tmp->mysys_var) - pthread_mutex_lock(&tmp->mysys_var->mutex); + if ((mysys_var= tmp->mysys_var)) + pthread_mutex_lock(&mysys_var->mutex); thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0); thd_info->state_info= (char*) (tmp->locked ? "Locked" : tmp->net.reading_or_writing ? @@ -1298,8 +1299,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) tmp->mysys_var && tmp->mysys_var->current_cond ? "Waiting on cond" : NullS); - if (tmp->mysys_var) - pthread_mutex_unlock(&tmp->mysys_var->mutex); + if (mysys_var) + pthread_mutex_unlock(&mysys_var->mutex); #if !defined(DONT_USE_THR_ALARM) && ! defined(SCO) if (pthread_kill(tmp->real_id,0)) @@ -1444,6 +1445,9 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, break; case SHOW_LONGLONG: end= longlong10_to_str(*(longlong*) value, buff, 10); + break; + case SHOW_HA_ROWS: + end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10); break; case SHOW_BOOL: end= strmov(buff, *(bool*) value ? "ON" : "OFF"); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b72b722e010..1f4657fb55f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -46,7 +46,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, ** This will wait for all users to free the table before dropping it *****************************************************************************/ -int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) +int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, + my_bool drop_temporary) { int error; DBUG_ENTER("mysql_rm_table"); @@ -57,7 +58,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) thd->mysys_var->current_cond= &COND_refresh; VOID(pthread_mutex_lock(&LOCK_open)); - if (global_read_lock) + if (!drop_temporary && global_read_lock) { if (thd->global_read_lock) { @@ -72,7 +73,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) } } - error=mysql_rm_table_part2(thd,tables,if_exists,0); + error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, 0); err: pthread_mutex_unlock(&LOCK_open); @@ -91,14 +92,15 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, - bool dont_log_query) + bool drop_temporary, bool dont_log_query) { int error; thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; VOID(pthread_mutex_lock(&LOCK_open)); - error=mysql_rm_table_part2(thd,tables, if_exists, dont_log_query); + error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, + dont_log_query); pthread_mutex_unlock(&LOCK_open); VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh @@ -111,6 +113,17 @@ int mysql_rm_table_part2_with_lock(THD *thd, } /* + Execute the drop of a normal or temporary table + + SYNOPSIS + mysql_rm_table_part2() + thd Thread handler + tables Tables to drop + if_exists If set, don't give an error if table doesn't exists. + In this case we give an warning of level 'NOTE' + drop_temporary Only drop temporary tables + dont_log_query Don't log the query + TODO: When logging to the binary log, we should log tmp_tables and transactional tables as separate statements if we @@ -120,10 +133,15 @@ int mysql_rm_table_part2_with_lock(THD *thd, The current code only writes DROP statements that only uses temporary tables to the cache binary log. This should be ok on most cases, but not all. + + RETURN + 0 ok + 1 Error + -1 Thread was killed */ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, - bool dont_log_query) + bool drop_temporary, bool dont_log_query) { TABLE_LIST *table; char path[FN_REFLEN]; @@ -142,26 +160,28 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, continue; // removed temporary table } - abort_locked_tables(thd,db,table->real_name); - while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed) - { - dropping_tables++; - (void) pthread_cond_wait(&COND_refresh,&LOCK_open); - dropping_tables--; - } - drop_locked_tables(thd,db,table->real_name); - if (thd->killed) - DBUG_RETURN(-1); - - /* remove form file and isam files */ - strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext, - NullS); - (void) unpack_filename(path,path); error=0; + if (!drop_temporary) + { + abort_locked_tables(thd,db,table->real_name); + while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed) + { + dropping_tables++; + (void) pthread_cond_wait(&COND_refresh,&LOCK_open); + dropping_tables--; + } + drop_locked_tables(thd,db,table->real_name); + if (thd->killed) + DBUG_RETURN(-1); - table_type=get_table_type(path); + /* remove form file and isam files */ + strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext, + NullS); + (void) unpack_filename(path,path); - if (access(path,F_OK)) + table_type=get_table_type(path); + } + if (drop_temporary || access(path,F_OK)) { if (if_exists) store_warning(thd, ER_BAD_TABLE_ERROR, table->real_name); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index de5cb9ef45b..bf98ab7f7cb 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -416,8 +416,6 @@ int mysql_multi_update(THD *thd, (ORDER *)NULL, options | SELECT_NO_JOIN_CACHE, result, unit, select_lex, 0); - -end: delete result; DBUG_RETURN(res); } @@ -631,7 +629,6 @@ bool multi_update::send_data(List<Item> ¬_used_values) TABLE_LIST *cur_table; DBUG_ENTER("multi_update::send_data"); - found++; for (cur_table= update_tables; cur_table ; cur_table= cur_table->next) { TABLE *table= cur_table->table; @@ -647,6 +644,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) store_record(table,1); if (fill_record(*fields_for_table[offset], *values_for_table[offset])) DBUG_RETURN(1); + found++; if (compare_record(table, thd->query_id)) { int error; @@ -673,7 +671,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) int error; TABLE *tmp_table= tmp_tables[offset]; fill_record(tmp_table->field+1, *values_for_table[offset]); - + found++; /* Store pointer to row */ memcpy((char*) tmp_table->field[0]->ptr, (char*) table->file->ref, table->file->ref_length); @@ -772,7 +770,6 @@ int multi_update::do_updates(bool from_send_error) continue; // May happen on dup key goto err; } - found++; if ((local_error= table->file->rnd_pos(table->record[0], ref_pos))) goto err; table->status|= STATUS_UPDATED; diff --git a/sql/structs.h b/sql/structs.h index 604be6fcc6e..59b9335a5c4 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -130,7 +130,7 @@ enum SHOW_TYPE SHOW_UNDEF, SHOW_LONG, SHOW_LONGLONG, SHOW_INT, SHOW_CHAR, SHOW_CHAR_PTR, SHOW_BOOL, SHOW_MY_BOOL, SHOW_OPENTABLES, SHOW_STARTTIME, SHOW_QUESTION, - SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, + SHOW_LONG_CONST, SHOW_INT_CONST, SHOW_HAVE, SHOW_SYS, SHOW_HA_ROWS, #ifdef HAVE_OPENSSL SHOW_SSL_CTX_SESS_ACCEPT, SHOW_SSL_CTX_SESS_ACCEPT_GOOD, SHOW_SSL_GET_VERSION, SHOW_SSL_CTX_GET_SESSION_CACHE_MODE, |