diff options
author | marko@hundin.mysql.fi <> | 2004-10-04 15:17:32 +0300 |
---|---|---|
committer | marko@hundin.mysql.fi <> | 2004-10-04 15:17:32 +0300 |
commit | c0531d70f67926f7e14639ca623217b026715312 (patch) | |
tree | 3b334216d42223c985d2097035d89e1a2452a071 /sql | |
parent | c03049dfd98c91e5c5e37b8c7ba55279e63d2c71 (diff) | |
parent | d67cd1af90ffe4e596a6ba4efecdab7bc7090d26 (diff) | |
download | mariadb-git-c0531d70f67926f7e14639ca623217b026715312.tar.gz |
Merge marko@build.mysql.com:/home/bk/mysql-4.0
into hundin.mysql.fi:/home/marko/k/mysql-4.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 24 | ||||
-rw-r--r-- | sql/field.h | 13 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 24 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 9 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 1 | ||||
-rw-r--r-- | sql/mysqld.cc | 5 | ||||
-rw-r--r-- | sql/net_pkg.cc | 4 | ||||
-rw-r--r-- | sql/sql_base.cc | 25 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 40 | ||||
-rw-r--r-- | sql/sql_show.cc | 14 | ||||
-rw-r--r-- | sql/sql_table.cc | 12 | ||||
-rw-r--r-- | sql/sql_update.cc | 104 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 12 | ||||
-rw-r--r-- | sql/stacktrace.c | 2 | ||||
-rw-r--r-- | sql/table.h | 8 |
16 files changed, 232 insertions, 67 deletions
diff --git a/sql/field.cc b/sql/field.cc index 394d53238c2..69ee6606be4 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2467,8 +2467,7 @@ void Field_double::sql_type(String &res) const enum Item_result Field_timestamp::result_type() const { - return (!current_thd->variables.new_mode && - (field_length == 8 || field_length == 14) ? INT_RESULT : + return ((field_length == 8 || field_length == 14) ? INT_RESULT : STRING_RESULT); } @@ -2480,6 +2479,9 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, :Field_num(ptr_arg, len_arg, (uchar*) 0,0, unireg_check_arg, field_name_arg, table_arg, 0, 1, 1) +#if MYSQL_VERSION_ID < 40100 + , orig_field_length(len_arg) +#endif { if (table && !table->timestamp_field) { @@ -2697,7 +2699,7 @@ String *Field_timestamp::val_str(String *val_buffer, time_t time_arg; struct tm *l_time; struct tm tm_tmp; - my_bool new_format= (current_thd->variables.new_mode) || field_length == 19, + my_bool new_format= field_length == 19, full_year=(field_length == 8 || field_length == 14 || new_format); int real_field_length= new_format ? 19 : field_length; @@ -2859,22 +2861,6 @@ void Field_timestamp::set_time() longstore(ptr,tmp); } -/* - This is an exact copy of Field_num except that 'length' is depending - on --new mode -*/ - -void Field_timestamp::make_field(Send_field *field) -{ - field->table_name=table_name; - field->col_name=field_name; - /* If --new, then we are using "YYYY-MM-DD HH:MM:SS" format */ - field->length= current_thd->variables.new_mode ? 19 : field_length; - field->type=type(); - field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; - field->decimals=dec; -} - /**************************************************************************** ** time type diff --git a/sql/field.h b/sql/field.h index d25ce8d4774..c42f5f63f0c 100644 --- a/sql/field.h +++ b/sql/field.h @@ -546,6 +546,13 @@ public: class Field_timestamp :public Field_num { +#if MYSQL_VERSION_ID < 40100 + /* + We save the original field length here because field_length is + changed to a mock value in case when the 'new_mode' is in effect. + */ + uint32 orig_field_length; +#endif public: Field_timestamp(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const char *field_name_arg, @@ -587,7 +594,11 @@ public: void fill_and_store(char *from,uint len); bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); - void make_field(Send_field *field); + +#if MYSQL_VERSION_ID < 40100 + friend TABLE *open_table(THD *thd,const char *db,const char *table_name, + const char *alias,bool *refresh); +#endif }; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index d5bbf9b5a92..2b7b8f436b1 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1000,9 +1000,27 @@ int ha_myisam::delete_table(const char *name) int ha_myisam::external_lock(THD *thd, int lock_type) { - return mi_lock_database(file, !table->tmp_table ? - lock_type : ((lock_type == F_UNLCK) ? - F_UNLCK : F_EXTRA_LCK)); + int rc; + + while ((! (rc= mi_lock_database(file, !table->tmp_table ? + lock_type : ((lock_type == F_UNLCK) ? + F_UNLCK : F_EXTRA_LCK)))) && + mi_is_crashed(file) && (myisam_recover_options != HA_RECOVER_NONE)) + { + /* + check_and_repair() implicitly write locks the table, unless a + LOCK TABLES is in effect. It should be safer to always write lock here. + The implicit lock by check_and_repair() will then be a no-op. + check_and_repair() does not restore the original lock, but unlocks the + table. So we have to get the requested lock type again. And then to + check, if the table has been crashed again meanwhile by another server. + If anything fails, we break. + */ + if (((lock_type != F_WRLCK) && (rc= mi_lock_database(file, F_WRLCK))) || + (rc= check_and_repair(thd))) + break; + } + return rc; } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 013304d9df5..fbc1ad97e76 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -654,6 +654,15 @@ Item_func_nullif::val_str(String *str) return res; } + +bool +Item_func_nullif::is_null() +{ + if (!(this->*cmp_func)()) + return null_value=1; + return 0; +} + /* CASE expression Return the matching ITEM or NULL if all compares (including else) failed diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 236ebb8d28b..8f1aa525190 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -240,6 +240,7 @@ public: void fix_length_and_dec(); const char *func_name() const { return "nullif"; } table_map not_null_tables() const { return 0; } + bool is_null(); }; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 06599cf0ea7..834cff0d869 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2080,8 +2080,7 @@ static void check_data_home(const char *path) /* ARGSUSED */ -extern "C" int my_message_sql(uint error, const char *str, - myf MyFlags __attribute__((unused))) +extern "C" int my_message_sql(uint error, const char *str, myf MyFlags) { NET *net; DBUG_ENTER("my_message_sql"); @@ -2094,7 +2093,7 @@ extern "C" int my_message_sql(uint error, const char *str, net->last_errno=error ? error : ER_UNKNOWN_ERROR; } } - else + if (!net || MyFlags & ME_NOREFRESH) sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */ DBUG_RETURN(0); } diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index cc9147fe90a..df77d0347f2 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -132,6 +132,10 @@ net_printf(NET *net, uint errcode, ...) length=sizeof(net->last_error)-1; /* purecov: inspected */ va_end(args); + /* Replication slave relies on net->last_* to see if there was error */ + net->last_errno= errcode; + strmake(net->last_error, text_pos, sizeof(net->last_error)-1); + if (net->vio == 0) { if (thd && thd->bootstrap) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8fd7273fd78..c9d6ca87fdb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -941,6 +941,31 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, for (uint i=0 ; i < table->fields ; i++) table->field[i]->table_name=table->table_name; } +#if MYSQL_VERSION_ID < 40100 + /* + If per-connection "new" variable (represented by variables.new_mode) + is set then we should pretend that the length of TIMESTAMP field is 19. + The cheapest (from perfomance viewpoint) way to achieve that is to set + field_length of all Field_timestamp objects in a table after opening + it (to 19 if new_mode is true or to original field length otherwise). + We save value of new_mode variable in TABLE::timestamp_mode to + not perform this setup if new_mode value is the same between sequential + table opens. + */ + my_bool new_mode= thd->variables.new_mode; + if (table->timestamp_mode != new_mode) + { + for (uint i=0 ; i < table->fields ; i++) + { + Field *field= table->field[i]; + + if (field->type() == FIELD_TYPE_TIMESTAMP) + field->field_length= new_mode ? 19 : + ((Field_timestamp *)(field))->orig_field_length; + } + table->timestamp_mode= new_mode; + } +#endif /* These variables are also set in reopen_table() */ table->tablenr=thd->current_tablenr++; table->used_fields=0; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 555e63b9e32..92193e3abf2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -282,6 +282,8 @@ multi_delete::initialize_tables(JOIN *join) walk=walk->next; /* Don't use KEYREAD optimization on this table */ tbl->no_keyread=1; + /* Don't use record cache */ + tbl->no_cache= 1; tbl->used_keys= 0; if (tbl->file->has_transactions()) log_delayed= transactional_tables= 1; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e95c52f1e48..9e0853a370b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1927,21 +1927,26 @@ mysql_execute_command(void) send_error(&thd->net,ER_WRONG_VALUE_COUNT); DBUG_VOID_RETURN; } - if (select_lex->table_list.elements == 1) - { - if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) - goto error; /* purecov: inspected */ + if (check_one_table_access(thd, UPDATE_ACL, tables, 0)) + goto error; /* purecov: inspected */ - res= mysql_update(thd,tables, - select_lex->item_list, - lex->value_list, - select_lex->where, - (ORDER *) select_lex->order_list.first, - select_lex->select_limit, - lex->duplicates); + res= mysql_update(thd,tables, + select_lex->item_list, + lex->value_list, + select_lex->where, + (ORDER *) select_lex->order_list.first, + select_lex->select_limit, + lex->duplicates); + break; + case SQLCOM_MULTI_UPDATE: + if (check_db_used(thd,tables)) + goto error; + if (select_lex->item_list.elements != lex->value_list.elements) + { + send_error(&thd->net,ER_WRONG_VALUE_COUNT); + DBUG_VOID_RETURN; } - else { const char *msg= 0; TABLE_LIST *table; @@ -3242,7 +3247,18 @@ bool add_field_to_list(char *field_name, enum_field_types type, } break; case FIELD_TYPE_TIMESTAMP: +#if MYSQL_VERSION_ID < 40100 + /* + When in in --new mode, we should create TIMESTAMP(19) fields by default; + otherwise we will have problems with ALTER TABLE changing lengths of + existing TIMESTAMP fields to 19 and adding new fields with length 14. + */ + if (thd->variables.new_mode) + new_field->length= 19; + else if (!length) +#else if (!length) +#endif new_field->length= 14; // Full date YYYYMMDDHHMMSS else if (new_field->length != 19) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6784cd64465..2506033cda5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -193,27 +193,23 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, { /* Return databases */ #ifdef USE_SYMDIR char *ext; + char buff[FN_REFLEN]; if (my_use_symdir && !strcmp(ext=fn_ext(file->name), ".sym")) { /* Only show the sym file if it points to a directory */ - char buff[FN_REFLEN], *end; - MY_STAT status; + char *end; *ext=0; /* Remove extension */ unpack_dirname(buff, file->name); end= strend(buff); if (end != buff && end[-1] == FN_LIBCHAR) end[-1]= 0; // Remove end FN_LIBCHAR - if (!my_stat(buff, &status, MYF(0)) || - !MY_S_ISDIR(status.st_mode)) - continue; - } - else + if (!my_stat(buff, file->mystat, MYF(0))) + continue; + } #endif - { if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat->st_mode) || (wild && wild_compare(file->name,wild, 0))) continue; - } } else { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e2e186abb0d..0dd5c65bf79 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2208,7 +2208,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (!(copy= new Copy_field[to->fields])) DBUG_RETURN(-1); /* purecov: inspected */ - to->file->external_lock(thd,F_WRLCK); + if (to->file->external_lock(thd, F_WRLCK)) + { + /* We must always unlock, even when lock failed. */ + (void) to->file->external_lock(thd, F_UNLCK); + DBUG_RETURN(-1); + } to->file->extra(HA_EXTRA_WRITE_CACHE); from->file->info(HA_STATUS_VARIABLE); to->file->deactivate_non_unique_index(from->file->records); @@ -2308,11 +2313,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, error=1; if (ha_commit(thd)) error=1; - if (to->file->external_lock(thd,F_UNLCK)) - error=1; err: free_io_cache(from); *copied= found_count; *deleted=delete_count; + /* we must always unlock the table on return. */ + if (to->file->external_lock(thd,F_UNLCK)) + error=1; DBUG_RETURN(error > 0 ? -1 : 0); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d51c81ee127..a17742df03b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -401,25 +401,101 @@ int mysql_multi_update(THD *thd, int res; multi_update *result; TABLE_LIST *tl; + const bool locked= !(thd->locked_tables); DBUG_ENTER("mysql_multi_update"); - if ((res=open_and_lock_tables(thd,table_list))) - DBUG_RETURN(res); + for (;;) + { + table_map update_map= 0; + int tnr= 0; + + if ((res= open_tables(thd, table_list))) + DBUG_RETURN(res); - thd->select_limit=HA_POS_ERROR; + /* + Only need to call lock_tables if (thd->locked_tables == NULL) + */ + if (locked && ((res= lock_tables(thd, table_list)))) + DBUG_RETURN(res); - /* - Ensure that we have update privilege for all tables and columns in the - SET part - */ - for (tl= table_list ; tl ; tl=tl->next) - { - TABLE *table= tl->table; - table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); - } + thd->select_limit=HA_POS_ERROR; - if (setup_fields(thd, table_list, *fields, 1, 0, 0)) - DBUG_RETURN(-1); + /* + Ensure that we have update privilege for all tables and columns in the + SET part + While we are here, initialize the table->map field. + */ + for (tl= table_list ; tl ; tl=tl->next) + { + TABLE *table= tl->table; + table->grant.want_privilege= (UPDATE_ACL & ~table->grant.privilege); + table->map= (table_map) 1 << (tnr++); + } + + if (!setup_fields(thd, table_list, *fields, 1, 0, 0)) + { + List_iterator_fast<Item> field_it(*fields); + Item_field *item; + + while ((item= (Item_field *) field_it++)) + update_map|= item->used_tables(); + + DBUG_PRINT("info",("update_map=0x%08x", update_map)); + } + else + DBUG_RETURN(-1); + + /* + Unlock the tables in preparation for relocking + */ + if (locked) + { + pthread_mutex_lock(&LOCK_open); + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + pthread_mutex_unlock(&LOCK_open); + } + + /* + Set the table locking strategy according to the update map + */ + for (tl= table_list ; tl ; tl=tl->next) + { + TABLE *table= tl->table; + if (update_map & table->map) + { + DBUG_PRINT("info",("setting table `%s` for update", tl->alias)); + tl->lock_type= thd->lex.lock_option; + tl->updating= 1; + } + else + { + DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias)); + tl->lock_type= TL_READ; + tl->updating= 0; + } + if (locked) + tl->table->reginfo.lock_type= tl->lock_type; + } + + /* + Relock the tables + */ + if (!(res=lock_tables(thd,table_list))) + break; + + if (!locked) + DBUG_RETURN(res); + + List_iterator_fast<Item> field_it(*fields); + Item_field *item; + + while ((item= (Item_field *) field_it++)) + /* item->cleanup(); XXX Use this instead in MySQL 4.1+ */ + item->field= item->result_field= 0; + + close_thread_tables(thd); + } /* Count tables and setup timestamp handling diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b073db2e36..7b72c73a915 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2751,10 +2751,18 @@ update: lex->select->order_list.next= (byte**) &lex->select->order_list.first; } opt_low_priority opt_ignore join_table_list - SET update_list where_clause opt_order_clause delete_limit_clause + SET update_list { - set_lock_for_tables($3); + if (Lex->select->table_list.elements > 1) + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_MULTI_UPDATE; + lex->lock_option= $3; + } + else + set_lock_for_tables($3); } + where_clause opt_order_clause delete_limit_clause {} ; update_list: diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 73a7ecdc7ba..fa9ab093f26 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -197,7 +197,7 @@ terribly wrong...\n"); fprintf(stderr, "Stack trace seems successful - bottom reached\n"); end: - fprintf(stderr, "Please read http://www.mysql.com/doc/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ + fprintf(stderr, "Please read http://dev.mysql.com/doc/mysql/en/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ stack trace is much more helpful in diagnosing the problem, so please do \n\ resolve it\n"); } diff --git a/sql/table.h b/sql/table.h index f3b0e148cc0..84df7ba127e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -106,6 +106,14 @@ struct st_table { *found_next_number_field, /* Set on open */ *rowid_field; Field_timestamp *timestamp_field; +#if MYSQL_VERSION_ID < 40100 + /* + Indicates whenever we have to set field_length members of all TIMESTAMP + fields to 19 (to honour 'new_mode' variable) or to original + field_length values. + */ + my_bool timestamp_mode; +#endif my_string comment; /* Comment about table */ REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; |