summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <marko@hundin.mysql.fi>2005-01-31 09:34:34 +0200
committerunknown <marko@hundin.mysql.fi>2005-01-31 09:34:34 +0200
commit30025f3fdc7479a5aff9922fbc1b92610f7c03e7 (patch)
tree64c0ee08fa11d2b6a438ade00ec73775b8ba96e4 /sql
parent0b7ca5e847633d6a97911ac4bd7584e837fc345e (diff)
parent934fde094cc092baa110dc3821e098d3d286e0c6 (diff)
downloadmariadb-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.h3
-rw-r--r--sql/sql_parse.cc81
-rw-r--r--sql/sql_update.cc51
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