summaryrefslogtreecommitdiff
path: root/sql/sql_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r--sql/sql_base.cc171
1 files changed, 94 insertions, 77 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index bc9aa50cb82..6a99d5d1541 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -360,7 +360,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
*/
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
- thd->proc_info="Flushing tables";
+ thd_proc_info(thd, "Flushing tables");
close_old_data_files(thd,thd->open_tables,1,1);
mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL,
@@ -416,7 +416,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- thd->proc_info=0;
+ thd_proc_info(thd, 0);
pthread_mutex_unlock(&thd->mysys_var->mutex);
}
DBUG_RETURN(result);
@@ -609,7 +609,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
good idea to turn off OPTION_TABLE_LOCK flag.
*/
DBUG_ASSERT(thd->lex->requires_prelocking());
- thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ thd->options&= ~(OPTION_TABLE_LOCK);
}
DBUG_VOID_RETURN;
@@ -787,7 +787,7 @@ void close_temporary_tables(THD *thd)
due to special characters
*/
append_identifier(thd, &s_query, table->s->table_name,
- strlen(table->s->table_name));
+ (uint) strlen(table->s->table_name));
s_query.q_append(',');
next= table->next;
close_temporary(table, 1);
@@ -797,19 +797,10 @@ void close_temporary_tables(THD *thd)
thd->variables.character_set_client= system_charset_info;
Query_log_event qinfo(thd, s_query.ptr(),
s_query.length() - 1 /* to remove trailing ',' */,
- 0, FALSE);
+ 0, FALSE, THD::NOT_KILLED);
qinfo.db= db.ptr();
thd->variables.character_set_client= cs_save;
- /*
- Imagine the thread had created a temp table, then was doing a SELECT, and
- the SELECT was killed. Then it's not clever to mark the statement above as
- "killed", because it's not really a statement updating data, and there
- are 99.99% chances it will succeed on slave.
- If a real update (one updating a persistent table) was killed on the
- master, then this real update will be logged with error_code=killed,
- rightfully causing the slave to stop.
- */
- qinfo.error_code= 0;
+ DBUG_ASSERT(qinfo.error_code == 0);
mysql_bin_log.write(&qinfo);
}
else
@@ -1216,7 +1207,7 @@ void wait_for_refresh(THD *thd)
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
proc_info=thd->proc_info;
- thd->proc_info="Waiting for table";
+ thd_proc_info(thd, "Waiting for table");
if (!thd->killed)
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
@@ -1224,7 +1215,7 @@ void wait_for_refresh(THD *thd)
pthread_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= 0;
thd->mysys_var->current_cond= 0;
- thd->proc_info= proc_info;
+ thd_proc_info(thd, proc_info);
pthread_mutex_unlock(&thd->mysys_var->mutex);
DBUG_VOID_RETURN;
}
@@ -1570,7 +1561,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
it can not be cloned. Emit an error for an unsupported behaviour.
*/
if (table->query_id == thd->query_id ||
- thd->prelocked_mode && table->query_id)
+ (thd->prelocked_mode && table->query_id))
{
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
DBUG_RETURN(0);
@@ -1601,27 +1592,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{ // Using table locks
TABLE *best_table= 0;
int best_distance= INT_MIN;
- bool check_if_used= thd->prelocked_mode &&
- ((int) table_list->lock_type >=
- (int) TL_WRITE_ALLOW_WRITE);
for (table=thd->open_tables; table ; table=table->next)
{
if (table->s->key_length == key_length &&
!memcmp(table->s->table_cache_key, key, key_length))
{
- if (check_if_used && table->query_id &&
- table->query_id != thd->query_id)
- {
- /*
- If we are in stored function or trigger we should ensure that
- we won't change table that is already used by calling statement.
- So if we are opening table for writing, we should check that it
- is not already open by some calling stamement.
- */
- my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
- table->s->table_name);
- DBUG_RETURN(0);
- }
if (!my_strcasecmp(system_charset_info, table->alias, alias) &&
table->query_id != thd->query_id && /* skip tables already used */
!(thd->prelocked_mode && table->query_id))
@@ -1640,18 +1615,18 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
distance > 0 - we have lock mode higher then we require
distance == 0 - we have lock mode exactly which we need
*/
- if (best_distance < 0 && distance > best_distance ||
- distance >= 0 && distance < best_distance)
+ if ((best_distance < 0 && distance > best_distance) ||
+ (distance >= 0 && distance < best_distance))
{
best_distance= distance;
best_table= table;
- if (best_distance == 0 && !check_if_used)
+ if (best_distance == 0)
{
/*
- If we have found perfect match and we don't need to check that
- table is not used by one of calling statements (assuming that
- we are inside of function or trigger) we can finish iterating
- through open tables list.
+ We have found a perfect match and can finish iterating
+ through open tables list. Check for table use conflict
+ between calling statement and SP/trigger is done in
+ lock_tables().
*/
break;
}
@@ -2107,7 +2082,10 @@ bool reopen_table(TABLE *table,bool locked)
for (key=0 ; key < table->s->keys ; key++)
{
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
+ {
table->key_info[key].key_part[part].field->table= table;
+ table->key_info[key].key_part[part].field->orig_table= table;
+ }
}
if (table->triggers)
table->triggers->set_table(table);
@@ -2325,8 +2303,8 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
search= (TABLE*) hash_next(&open_cache, (byte*) key,
key_length, &state))
{
- if (search->locked_by_name && wait_for_name_lock ||
- search->is_name_opened() && search->needs_reopen_or_name_lock())
+ if ((search->locked_by_name && wait_for_name_lock) ||
+ (search->is_name_opened() && search->needs_reopen_or_name_lock()))
return 1; // Table is used
}
} while ((table=table->next));
@@ -2341,7 +2319,7 @@ bool wait_for_tables(THD *thd)
bool result;
DBUG_ENTER("wait_for_tables");
- thd->proc_info="Waiting for tables";
+ thd_proc_info(thd, "Waiting for tables");
pthread_mutex_lock(&LOCK_open);
while (!thd->killed)
{
@@ -2357,12 +2335,12 @@ bool wait_for_tables(THD *thd)
else
{
/* Now we can open all tables without any interference */
- thd->proc_info="Reopen tables";
+ thd_proc_info(thd, "Reopen tables");
thd->version= refresh_version;
result=reopen_tables(thd,0,0);
}
pthread_mutex_unlock(&LOCK_open);
- thd->proc_info=0;
+ thd_proc_info(thd, 0);
DBUG_RETURN(result);
}
@@ -2580,7 +2558,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
{
end = strxmov(strmov(query, "DELETE FROM `"),
db,"`.`",name,"`", NullS);
- Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
+ Query_log_event qinfo(thd, query, (ulong)(end-query),
+ 0, FALSE, THD::NOT_KILLED);
mysql_bin_log.write(&qinfo);
my_free(query, MYF(0));
}
@@ -2663,7 +2642,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
restart:
*counter= 0;
query_tables_last_own= 0;
- thd->proc_info="Opening tables";
+ thd_proc_info(thd, "Opening tables");
/*
If we are not already executing prelocked statement and don't have
@@ -2891,7 +2870,7 @@ process_view_routines:
}
err:
- thd->proc_info=0;
+ thd_proc_info(thd, 0);
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
if (query_tables_last_own)
@@ -2946,9 +2925,9 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
lock_type Lock to use for open
NOTE
- This function don't do anything like SP/SF/views/triggers analysis done
- in open_tables(). It is intended for opening of only one concrete table.
- And used only in special contexts.
+ This function doesn't do anything like SP/SF/views/triggers analysis done
+ in open_tables()/lock_tables(). It is intended for opening of only one
+ concrete table. And used only in special contexts.
RETURN VALUES
table Opened table
@@ -2965,7 +2944,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
bool refresh;
DBUG_ENTER("open_ltable");
- thd->proc_info="Opening table";
+ thd_proc_info(thd, "Opening table");
thd->current_tablenr= 0;
/* open_ltable can be used only for BASIC TABLEs */
table_list->required_type= FRMTYPE_TABLE;
@@ -2992,7 +2971,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
table= 0;
}
}
- thd->proc_info=0;
+ thd_proc_info(thd, 0);
DBUG_RETURN(table);
}
@@ -3212,7 +3191,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
{
if (thd->lex->requires_prelocking())
{
- thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ thd->options&= ~(OPTION_TABLE_LOCK);
thd->in_lock_tables=0;
}
DBUG_RETURN(-1);
@@ -3245,7 +3224,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
ha_rollback_stmt(thd);
mysql_unlock_tables(thd, thd->locked_tables);
thd->locked_tables= 0;
- thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
+ thd->options&= ~(OPTION_TABLE_LOCK);
DBUG_RETURN(-1);
}
}
@@ -3264,8 +3243,36 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
TABLE_LIST *first_not_own= thd->lex->first_not_own_table();
for (table= tables; table != first_not_own; table= table->next_global)
{
- if (!table->placeholder() &&
- check_lock_and_start_stmt(thd, table->table, table->lock_type))
+ if (table->placeholder())
+ continue;
+
+ /*
+ In a stored function or trigger we should ensure that we won't change
+ a table that is already used by the calling statement.
+ */
+ if (thd->prelocked_mode &&
+ table->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ for (TABLE* opentab= thd->open_tables; opentab; opentab= opentab->next)
+ {
+ /*
+ issue an error if the tables are the same (by key comparison),
+ but query_id isn't
+ */
+ if (opentab->query_id &&
+ table->table->query_id != opentab->query_id &&
+ table->table->s->key_length == opentab->s->key_length &&
+ !memcmp(table->table->s->table_cache_key,
+ opentab->s->table_cache_key, opentab->s->key_length))
+ {
+ my_error(ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG, MYF(0),
+ table->table->s->table_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
ha_rollback_stmt(thd);
DBUG_RETURN(-1);
@@ -3692,7 +3699,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
if (field_ptr && *field_ptr)
{
- *cached_field_index_ptr= field_ptr - table->field;
+ *cached_field_index_ptr= (uint) (field_ptr - table->field);
field= *field_ptr;
}
else
@@ -5093,7 +5100,13 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
/* make * substituting permanent */
SELECT_LEX *select_lex= thd->lex->current_select;
select_lex->with_wild= 0;
- select_lex->item_list= fields;
+ /*
+ The assignment below is translated to memcpy() call (at least on some
+ platforms). memcpy() expects that source and destination areas do not
+ overlap. That problem was detected by valgrind.
+ */
+ if (&select_lex->item_list != &fields)
+ select_lex->item_list= fields;
thd->restore_active_arena(arena, &backup);
}
@@ -5140,7 +5153,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
- if (!item->fixed && item->fix_fields(thd, it.ref()) ||
+ if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
(item= *(it.ref()))->check_cols(1))
{
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
@@ -5474,16 +5487,16 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
DBUG_ASSERT(tables->is_leaf_for_name_resolution());
- if (table_name && my_strcasecmp(table_alias_charset, table_name,
- tables->alias) ||
+ if ((table_name && my_strcasecmp(table_alias_charset, table_name,
+ tables->alias)) ||
(db_name && strcmp(tables->db,db_name)))
continue;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access rights to all fields to be inserted. */
- if (!((table && (table->grant.privilege & SELECT_ACL) ||
- tables->view && (tables->grant.privilege & SELECT_ACL))) &&
- !any_privileges)
+ if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL)) ||
+ (tables->view && (tables->grant.privilege & SELECT_ACL))) &&
+ !any_privileges)
{
field_iterator.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &field_iterator))
@@ -5513,6 +5526,10 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (!(item= field_iterator.create_item(thd)))
DBUG_RETURN(TRUE);
+ DBUG_ASSERT(item->fixed);
+ /* cache the table for the Item_fields inserted by expanding stars */
+ if (item->type() == Item::FIELD_ITEM && tables->cacheable_table)
+ ((Item_field *)item)->cached_table= tables;
if (!found)
{
@@ -5533,7 +5550,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
*/
if (any_privileges)
{
- DBUG_ASSERT(tables->field_translation == NULL && table ||
+ DBUG_ASSERT((tables->field_translation == NULL && table) ||
tables->is_natural_join);
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Item_field *fld= (Item_field*) item;
@@ -5678,7 +5695,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
if (*conds)
{
thd->where="where clause";
- if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) ||
+ if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) ||
(*conds)->check_cols(1))
goto err_no_arena;
}
@@ -5698,8 +5715,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
{
/* Make a join an a expression */
thd->where="on clause";
- if (!embedded->on_expr->fixed &&
- embedded->on_expr->fix_fields(thd, &embedded->on_expr) ||
+ if ((!embedded->on_expr->fixed &&
+ embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
embedded->on_expr->check_cols(1))
goto err_no_arena;
select_lex->cond_count++;
@@ -5854,8 +5871,8 @@ fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
enum trg_event_type event)
{
return (fill_record(thd, fields, values, ignore_errors) ||
- triggers && triggers->process_triggers(thd, event,
- TRG_ACTION_BEFORE, TRUE));
+ (triggers && triggers->process_triggers(thd, event,
+ TRG_ACTION_BEFORE, TRUE)));
}
@@ -5949,8 +5966,8 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
enum trg_event_type event)
{
return (fill_record(thd, ptr, values, ignore_errors) ||
- triggers && triggers->process_triggers(thd, event,
- TRG_ACTION_BEFORE, TRUE));
+ (triggers && triggers->process_triggers(thd, event,
+ TRG_ACTION_BEFORE, TRUE)));
}
@@ -5990,7 +6007,7 @@ my_bool mysql_rm_tmp_tables(void)
if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length))
{
char *ext= fn_ext(file->name);
- uint ext_len= strlen(ext);
+ size_t ext_len= strlen(ext);
uint filePath_len= my_snprintf(filePath, sizeof(filePath),
"%s%s", tmpdir, file->name);
if (!bcmp(reg_ext, ext, ext_len))
@@ -6222,7 +6239,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
Item_func_match *ifm;
DBUG_PRINT("info",("Performing FULLTEXT search"));
- thd->proc_info="FULLTEXT initialization";
+ thd_proc_info(thd, "FULLTEXT initialization");
while ((ifm=li++))
ifm->init_search(no_order);
@@ -6262,7 +6279,7 @@ open_new_frm(THD *thd, const char *path, const char *alias,
DBUG_ENTER("open_new_frm");
pathstr.str= (char*) path;
- pathstr.length= strlen(path);
+ pathstr.length= (uint) strlen(path);
if ((parser= sql_parse_prepare(&pathstr, mem_root, 1)))
{