summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authormarko@hundin.mysql.fi <>2004-10-04 15:17:32 +0300
committermarko@hundin.mysql.fi <>2004-10-04 15:17:32 +0300
commitc0531d70f67926f7e14639ca623217b026715312 (patch)
tree3b334216d42223c985d2097035d89e1a2452a071 /sql
parentc03049dfd98c91e5c5e37b8c7ba55279e63d2c71 (diff)
parentd67cd1af90ffe4e596a6ba4efecdab7bc7090d26 (diff)
downloadmariadb-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.cc24
-rw-r--r--sql/field.h13
-rw-r--r--sql/ha_myisam.cc24
-rw-r--r--sql/item_cmpfunc.cc9
-rw-r--r--sql/item_cmpfunc.h1
-rw-r--r--sql/mysqld.cc5
-rw-r--r--sql/net_pkg.cc4
-rw-r--r--sql/sql_base.cc25
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_parse.cc40
-rw-r--r--sql/sql_show.cc14
-rw-r--r--sql/sql_table.cc12
-rw-r--r--sql/sql_update.cc104
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/stacktrace.c2
-rw-r--r--sql/table.h8
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;