summaryrefslogtreecommitdiff
path: root/sql/sql_update.cc
diff options
context:
space:
mode:
authorunknown <antony@ltantony.rdg.cyberkinetica.homeunix.net>2004-10-03 00:20:47 +0100
committerunknown <antony@ltantony.rdg.cyberkinetica.homeunix.net>2004-10-03 00:20:47 +0100
commita49f5cae9ad6f4de7f5c2d9f8bbdbca270376af6 (patch)
tree2b6e8c65a6d12454985b9e836b6d1a7c203750bd /sql/sql_update.cc
parent799505216ff2fb29a48d7a609f8b392c8c6bb87c (diff)
downloadmariadb-git-a49f5cae9ad6f4de7f5c2d9f8bbdbca270376af6.tar.gz
Bug#4118: multi-table UPDATE takes WRITE lock on read table
Ensures that WRITE lock is not obtained on all tables referenced. mysql-test/r/lock_multi.result: Bug#4118 New test for multi-update locking mysql-test/r/multi_update.result: Bug#4118 Fix test mysql-test/t/lock_multi.test: Bug#4118 New test for multi-update locking mysql-test/t/multi_update.test: Bug#4118 Fix test sql/sql_parse.cc: Bug#4118 Split multi-update to its own case statement in sql_parse.cc sql/sql_update.cc: Bug#4118 Overview of locking checking: 1. Open and acquire READ lock 2. Check to see which tables need WRITE lock 3. Unlock tables and relock sql/sql_yacc.yy: Bug#4118 Split multi-update to its own case statement in sql_parse.cc
Diffstat (limited to 'sql/sql_update.cc')
-rw-r--r--sql/sql_update.cc104
1 files changed, 90 insertions, 14 deletions
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