diff options
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 171 |
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))) { |