diff options
author | unknown <marko@hundin.mysql.fi> | 2005-01-31 09:34:34 +0200 |
---|---|---|
committer | unknown <marko@hundin.mysql.fi> | 2005-01-31 09:34:34 +0200 |
commit | 30025f3fdc7479a5aff9922fbc1b92610f7c03e7 (patch) | |
tree | 64c0ee08fa11d2b6a438ade00ec73775b8ba96e4 /sql | |
parent | 0b7ca5e847633d6a97911ac4bd7584e837fc345e (diff) | |
parent | 934fde094cc092baa110dc3821e098d3d286e0c6 (diff) | |
download | mariadb-git-30025f3fdc7479a5aff9922fbc1b92610f7c03e7.tar.gz |
Merge marko@bk-internal.mysql.com:/home/bk/mysql-4.0
into hundin.mysql.fi:/home/marko/k/mysql-4.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 81 | ||||
-rw-r--r-- | sql/sql_update.cc | 51 |
3 files changed, 116 insertions, 19 deletions
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b123927d09e..cbbf3b843d3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -469,6 +469,9 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &values,COND *conds, ORDER *order, ha_rows limit, enum enum_duplicates handle_duplicates); +int mysql_multi_update_lock(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields); int mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, List<Item> *values, COND *conds, ulong options, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1aeb158dc11..275b76db177 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -56,6 +56,8 @@ static int check_for_max_user_connections(USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); +static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, + List<Item> *fields); static void mysql_init_query(THD *thd); static void remove_escape(char *name); static void refresh_status(void); @@ -1338,10 +1340,28 @@ mysql_execute_command(void) LEX *lex= &thd->lex; TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first; SELECT_LEX *select_lex = lex->select; + bool slave_fake_lock= 0; + MYSQL_LOCK *fake_prev_lock= 0; DBUG_ENTER("mysql_execute_command"); if (thd->slave_thread) { + if (lex->sql_command == SQLCOM_MULTI_UPDATE) + { + DBUG_PRINT("info",("need faked locked tables")); + + if (check_multi_update_lock(thd, tables, &select_lex->item_list)) + goto error; + + /* Fix for replication, the tables are opened and locked, + now we pretend that we have performed a LOCK TABLES action */ + + fake_prev_lock= thd->locked_tables; + if (thd->lock) + thd->locked_tables= thd->lock; + thd->lock= 0; + slave_fake_lock= 1; + } /* Skip if we are in the slave thread, some table rules have been given and the table list says the query should not be replicated @@ -1949,7 +1969,7 @@ mysql_execute_command(void) if (select_lex->item_list.elements != lex->value_list.elements) { send_error(&thd->net,ER_WRONG_VALUE_COUNT); - DBUG_VOID_RETURN; + goto error; } { const char *msg= 0; @@ -2641,6 +2661,14 @@ mysql_execute_command(void) send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); error: + if (unlikely(slave_fake_lock)) + { + DBUG_PRINT("info",("undoing faked lock")); + thd->lock= thd->locked_tables; + thd->locked_tables= fake_prev_lock; + if (thd->lock == thd->locked_tables) + thd->lock= 0; + } DBUG_VOID_RETURN; } @@ -3907,3 +3935,54 @@ bool check_simple_select() } return 0; } + +/* + Setup locking for multi-table updates. Used by the replication slave. + Replication slave SQL thread examines (all_tables_not_ok()) the + locking state of referenced tables to determine if the query has to + be executed or ignored. Since in multi-table update, the + 'default' lock is read-only, this lock is corrected early enough by + calling this function, before the slave decides to execute/ignore. + + SYNOPSIS + check_multi_update_lock() + thd Current thread + tables List of user-supplied tables + fields List of fields requiring update + + RETURN VALUES + 0 ok + 1 error +*/ +static bool check_multi_update_lock(THD *thd, TABLE_LIST *tables, + List<Item> *fields) +{ + bool res= 1; + TABLE_LIST *table; + DBUG_ENTER("check_multi_update_lock"); + + if (check_db_used(thd, tables)) + goto error; + + /* + Ensure that we have UPDATE or SELECT privilege for each table + The exact privilege is checked in mysql_multi_update() + */ + for (table= tables ; table ; table= table->next) + { + TABLE_LIST *save= table->next; + table->next= 0; + if (check_one_table_access(thd, UPDATE_ACL, table, 1) && + check_one_table_access(thd, SELECT_ACL, table, 0)) + goto error; + table->next= save; + } + + if (mysql_multi_update_lock(thd, tables, fields)) + goto error; + + res= 0; + +error: + DBUG_RETURN(res); +} diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4f7e34ec74f..b1b30a29639 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -403,26 +403,20 @@ static table_map get_table_map(List<Item> *items) } - /* - Setup multi-update handling and call SELECT to do the join + Prepare tables for multi-update + Analyse which tables need specific privileges and perform locking + as required */ -int mysql_multi_update(THD *thd, - TABLE_LIST *table_list, - List<Item> *fields, - List<Item> *values, - COND *conds, - ulong options, - enum enum_duplicates handle_duplicates) +int mysql_multi_update_lock(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields) { int res; - multi_update *result; TABLE_LIST *tl; const bool using_lock_tables= thd->locked_tables != 0; - DBUG_ENTER("mysql_multi_update"); - - thd->select_limit= HA_POS_ERROR; + DBUG_ENTER("mysql_multi_update_lock"); for (;;) { @@ -490,7 +484,7 @@ int mysql_multi_update(THD *thd, (grant_option && check_grant(thd, wants, tl, 0, 0))) { tl->next= save; - DBUG_RETURN(0); + DBUG_RETURN(1); } tl->next= save; } @@ -498,11 +492,7 @@ int mysql_multi_update(THD *thd, /* Relock the tables with the correct modes */ res= lock_tables(thd,table_list); if (using_lock_tables) - { - if (res) - DBUG_RETURN(res); break; // Don't have to do setup_field() - } /* We must setup fields again as the file may have been reopened @@ -535,6 +525,31 @@ int mysql_multi_update(THD *thd, */ close_thread_tables(thd); } + + DBUG_RETURN(res); +} + +/* + Setup multi-update handling and call SELECT to do the join +*/ + +int mysql_multi_update(THD *thd, + TABLE_LIST *table_list, + List<Item> *fields, + List<Item> *values, + COND *conds, + ulong options, + enum enum_duplicates handle_duplicates) +{ + int res; + TABLE_LIST *tl; + multi_update *result; + DBUG_ENTER("mysql_multi_update"); + + thd->select_limit= HA_POS_ERROR; + + if ((res= mysql_multi_update_lock(thd, table_list, fields))) + DBUG_RETURN(res); /* Count tables and setup timestamp handling |