diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_ndbcluster.cc | 2 | ||||
-rw-r--r-- | sql/item.h | 9 | ||||
-rw-r--r-- | sql/sql_table.cc | 25 | ||||
-rw-r--r-- | sql/sql_update.cc | 140 | ||||
-rw-r--r-- | sql/sql_view.cc | 10 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 25 | ||||
-rw-r--r-- | sql/table.cc | 2 |
7 files changed, 123 insertions, 90 deletions
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index af097366159..30be53f1ddb 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6134,7 +6134,7 @@ ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, retry: if(report_error) { - if (file) + if (file && pTrans) { reterr= file->ndb_err(pTrans); } diff --git a/sql/item.h b/sql/item.h index 62d6127f10b..6c41aa09f80 100644 --- a/sql/item.h +++ b/sql/item.h @@ -336,23 +336,18 @@ public: { save_table_list= context->table_list; save_first_name_resolution_table= context->first_name_resolution_table; - save_next_name_resolution_table= (context->first_name_resolution_table) ? - context->first_name_resolution_table-> - next_name_resolution_table : - NULL; save_resolve_in_select_list= context->resolve_in_select_list; save_next_local= table_list->next_local; + save_next_name_resolution_table= table_list->next_name_resolution_table; } /* Restore a name resolution context from saved state. */ void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) { table_list->next_local= save_next_local; + table_list->next_name_resolution_table= save_next_name_resolution_table; context->table_list= save_table_list; context->first_name_resolution_table= save_first_name_resolution_table; - if (context->first_name_resolution_table) - context->first_name_resolution_table-> - next_name_resolution_table= save_next_name_resolution_table; context->resolve_in_select_list= save_resolve_in_select_list; } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 51865d1d77c..6f57ac1ec42 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3163,19 +3163,30 @@ view_err: if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { - VOID(pthread_mutex_lock(&LOCK_open)); - switch (alter_info->keys_onoff) { case LEAVE_AS_IS: error= 0; break; case ENABLE: + /* + wait_while_table_is_used() ensures that table being altered is + opened only by this thread and that TABLE::TABLE_SHARE::version + of TABLE object corresponding to this table is 0. + The latter guarantees that no DML statement will open this table + until ALTER TABLE finishes (i.e. until close_thread_tables()) + while the fact that the table is still open gives us protection + from concurrent DDL statements. + */ + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; @@ -3188,6 +3199,16 @@ view_err: error= 0; } + VOID(pthread_mutex_lock(&LOCK_open)); + /* + Unlike to the above case close_cached_table() below will remove ALL + instances of TABLE from table cache (it will also remove table lock + held by this thread). So to make actual table renaming and writing + to binlog atomic we have to put them into the same critical section + protected by LOCK_open mutex. This also removes gap for races between + access() and mysql_rename_table() calls. + */ + if (!error && (new_name != table_name || new_db != db)) { thd->proc_info="rename"; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 76d4847f923..b85c617b12d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -24,8 +24,6 @@ #include "sp_head.h" #include "sql_trigger.h" -static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields); - /* Return 0 if row hasn't changed */ static bool compare_record(TABLE *table, query_id_t query_id) @@ -1040,27 +1038,73 @@ int multi_update::prepare(List<Item> ¬_used_values, for (i=0 ; i < table_count ; i++) set_if_bigger(max_fields, fields_for_table[i]->elements); copy_field= new Copy_field[max_fields]; + DBUG_RETURN(thd->is_fatal_error != 0); +} - /* - Mark all copies of tables that are updates to ensure that - init_read_record() will not try to enable a cache on them - The problem is that for queries like +/* + Check if table is safe to update on fly - UPDATE t1, t1 AS t2 SET t1.b=t2.c WHERE t1.a=t2.a; + SYNOPSIS + safe_update_on_fly() + thd Thread handler + join_tab How table is used in join + all_tables List of tables + fields Fields that are updated - the row buffer may contain things that doesn't match what is on disk - which will cause an error when reading a row. - (This issue is mostly relevent for MyISAM tables) - */ - for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) - { - TABLE *table=table_ref->table; - if ((tables_to_update & table->map) && - unique_table(thd, table_ref, update_tables)) - table->no_cache= 1; // Disable row cache + NOTES + We can update the first table in join on the fly if we know that + a row in this table will never be read twice. This is true under + the following conditions: + + - We are doing a table scan and the data is in a separate file (MyISAM) or + if we don't update a clustered key. + + - We are doing a range scan and we don't update the scan key or + the primary key for a clustered table handler. + + - Table is not joined to itself. + + When checking for above cases we also should take into account that + BEFORE UPDATE trigger potentially may change value of any field in row + being updated. + + WARNING + This code is a bit dependent of how make_join_readinfo() works. + + RETURN + 0 Not safe to update + 1 Safe to update +*/ + +static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab, + TABLE_LIST *table_ref, TABLE_LIST *all_tables, + List<Item> *fields) +{ + TABLE *table= join_tab->table; + if (unique_table(thd, table_ref, all_tables)) + return 0; + switch (join_tab->type) { + case JT_SYSTEM: + case JT_CONST: + case JT_EQ_REF: + return TRUE; // At most one matching row + case JT_REF: + case JT_REF_OR_NULL: + return !is_key_used(table, join_tab->ref.key, *fields); + case JT_ALL: + /* If range search on index */ + if (join_tab->quick) + return !join_tab->quick->is_keys_used(fields); + /* If scanning in clustered key */ + if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && + table->s->primary_key < MAX_KEY) + return !is_key_used(table, table->s->primary_key, *fields); + return TRUE; + default: + break; // Avoid compler warning } - DBUG_RETURN(thd->is_fatal_error != 0); + return FALSE; } @@ -1098,7 +1142,8 @@ multi_update::initialize_tables(JOIN *join) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); if (table == main_table) // First table in join { - if (safe_update_on_fly(join->join_tab, &temp_fields)) + if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables, + &temp_fields)) { table_to_update= main_table; // Update table on the fly continue; @@ -1149,63 +1194,6 @@ multi_update::initialize_tables(JOIN *join) DBUG_RETURN(0); } -/* - Check if table is safe to update on fly - - SYNOPSIS - safe_update_on_fly - join_tab How table is used in join - fields Fields that are updated - - NOTES - We can update the first table in join on the fly if we know that - a row in this table will never be read twice. This is true under - the following conditions: - - - We are doing a table scan and the data is in a separate file (MyISAM) or - if we don't update a clustered key. - - - We are doing a range scan and we don't update the scan key or - the primary key for a clustered table handler. - - When checking for above cases we also should take into account that - BEFORE UPDATE trigger potentially may change value of any field in row - being updated. - - WARNING - This code is a bit dependent of how make_join_readinfo() works. - - RETURN - 0 Not safe to update - 1 Safe to update -*/ - -static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields) -{ - TABLE *table= join_tab->table; - switch (join_tab->type) { - case JT_SYSTEM: - case JT_CONST: - case JT_EQ_REF: - return TRUE; // At most one matching row - case JT_REF: - case JT_REF_OR_NULL: - return !is_key_used(table, join_tab->ref.key, *fields); - case JT_ALL: - /* If range search on index */ - if (join_tab->quick) - return !join_tab->quick->is_keys_used(fields); - /* If scanning in clustered key */ - if ((table->file->table_flags() & HA_PRIMARY_KEY_IN_READ_INDEX) && - table->s->primary_key < MAX_KEY) - return !is_key_used(table, table->s->primary_key, *fields); - return TRUE; - default: - break; // Avoid compler warning - } - return FALSE; -} - multi_update::~multi_update() { diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0d6c38ee50e..18ef3eaf29c 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1135,13 +1135,17 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, /* Prepare a security context to check underlying objects of the view */ - Security_context *save_security_ctx= thd->security_ctx; if (!(table->view_sctx= (Security_context *) thd->stmt_arena->alloc(sizeof(Security_context)))) goto err; /* Assign the context to the tables referenced in the view */ - for (tbl= view_tables; tbl; tbl= tbl->next_global) - tbl->security_ctx= table->view_sctx; + if (view_tables) + { + DBUG_ASSERT(view_tables_tail); + for (tbl= view_tables; tbl != view_tables_tail->next_global; + tbl= tbl->next_global) + tbl->security_ctx= table->view_sctx; + } /* assign security context to SELECT name resolution contexts of view */ for(SELECT_LEX *sl= lex->all_selects_list; sl; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 92640ea58d6..0f29c3e1028 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3722,7 +3722,7 @@ alter_list_item: { Lex->alter_info.flags|= ALTER_FORCE; } - | order_clause + | alter_order_clause { LEX *lex=Lex; lex->alter_info.flags|= ALTER_ORDER; @@ -5943,6 +5943,29 @@ olap_opt: ; /* + Order by statement in ALTER TABLE +*/ + +alter_order_clause: + ORDER_SYM BY alter_order_list + ; + +alter_order_list: + alter_order_list ',' alter_order_item + | alter_order_item + ; + +alter_order_item: + simple_ident_nospvar order_dir + { + THD *thd= YYTHD; + bool ascending= ($2 == 1) ? true : false; + if (add_order_to_list(thd, $1, ascending)) + YYABORT; + } + ; + +/* Order by statement in select */ diff --git a/sql/table.cc b/sql/table.cc index 2a492a15722..5c72ac6ccbf 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -452,6 +452,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, memcpy(comment_pos, disk_buff+read_length-com_length, com_length); fix_type_pointers(&int_array, &share->fieldnames, 1, &names); + if (share->fieldnames.count != share->fields) + goto err; fix_type_pointers(&int_array, share->intervals, interval_count, &names); |