summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/ha_ndbcluster.cc2
-rw-r--r--sql/item.h9
-rw-r--r--sql/sql_table.cc25
-rw-r--r--sql/sql_update.cc140
-rw-r--r--sql/sql_view.cc10
-rw-r--r--sql/sql_yacc.yy25
-rw-r--r--sql/table.cc2
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> &not_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);