summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/lock_multi.result2
-rw-r--r--mysql-test/r/multi_update.result2
-rw-r--r--mysql-test/r/view.result6
-rw-r--r--mysql-test/t/multi_update.test4
-rw-r--r--mysql-test/t/view.test4
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/sql_base.cc13
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_derived.cc236
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_prepare.cc6
-rw-r--r--sql/sql_update.cc73
-rw-r--r--sql/table.h6
15 files changed, 216 insertions, 155 deletions
diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result
index 4eb4ff6cdc2..9eedbf50064 100644
--- a/mysql-test/r/lock_multi.result
+++ b/mysql-test/r/lock_multi.result
@@ -26,7 +26,7 @@ lock table t1 read;
update t1,t2 set c=a where b=d;
select c from t2;
c
-1
+2
drop table t1;
drop table t2;
create table t1 (a int);
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index df642b00673..5ef0ff8e82f 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -155,7 +155,6 @@ ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
-ERROR HY000: Table 't2' was locked with a READ lock and can't be updated
unlock tables;
LOCK TABLES t1 write, t2 write;
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
@@ -461,6 +460,7 @@ drop table t1, t2, t3;
create table t1 (col1 int);
create table t2 (col1 int);
update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
+ERROR HY000: You can't specify target table 't1' for update in FROM clause
delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
drop table t1,t2;
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 9e9ad7a6da6..3f12a582868 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -1339,16 +1339,14 @@ c
prepare stmt1 from "update v1,t1 set v1.s1=? where t1.s1=v1.s1";
set @arg='d';
execute stmt1 using @arg;
-ERROR HY000: Table 't1' is read only
select * from v1;
s1
-c
+d
set @arg='e';
execute stmt1 using @arg;
-ERROR HY000: Table 't1' is read only
select * from v1;
s1
-c
+e
deallocate prepare stmt1;
drop view v1;
drop table t1;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 8a213ab791c..1e1490cd3f1 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -159,8 +159,6 @@ LOCK TABLES t1 write, t2 read;
DELETE t1.*, t2.* FROM t1,t2 where t1.n=t2.n;
--error 1099
UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
---QQ This should not generate an error
---error 1099
UPDATE t1,t2 SET t1.d=t2.d WHERE t1.n=t2.n;
unlock tables;
LOCK TABLES t1 write, t2 write;
@@ -428,7 +426,7 @@ drop table t1, t2, t3;
#
create table t1 (col1 int);
create table t2 (col1 int);
--- QQ The following should give error 1093
+-- error 1093
update t1,t2 set t1.col1 = (select max(col1) from t1) where t1.col1 = t2.col1;
-- error 1093
delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2.col1;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 17077d1d086..8e38b5616f8 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -1300,13 +1300,9 @@ update v1,t1 set v1.s1='c' where t1.s1=v1.s1;
select * from v1;
prepare stmt1 from "update v1,t1 set v1.s1=? where t1.s1=v1.s1";
set @arg='d';
--- QQ This should not generate an error
---error 1036
execute stmt1 using @arg;
select * from v1;
set @arg='e';
--- QQ This should not generate an error
---error 1036
execute stmt1 using @arg;
select * from v1;
deallocate prepare stmt1;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 960f054b3ac..cd2cacad910 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -565,7 +565,11 @@ int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
int mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit);
-int mysql_handle_derived(LEX *lex);
+int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
+ st_lex *lex,
+ st_table_list *table));
+int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *t);
+int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
bool group, bool modify_item, uint convert_blob_length);
@@ -792,7 +796,6 @@ void wait_for_refresh(THD *thd);
int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
int open_and_lock_tables(THD *thd,TABLE_LIST *tables);
-void relink_tables_for_derived(THD *thd);
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index b3be1fc7338..959af0067e7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -44,6 +44,7 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
+static void relink_tables_for_multidelete(THD *thd);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
@@ -1857,21 +1858,23 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_and_lock_tables");
uint counter;
- if (open_tables(thd, tables, &counter) ||
+ if (open_tables(thd, tables, &counter) ||
lock_tables(thd, tables, counter) ||
- mysql_handle_derived(thd->lex))
+ mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(thd->net.report_error ? -1 : 1); /* purecov: inspected */
- relink_tables_for_derived(thd);
+ relink_tables_for_multidelete(thd);
DBUG_RETURN(0);
}
/*
Let us propagate pointers to open tables from global table list
- to table lists in particular selects if needed.
+ to table lists for multi-delete
*/
-void relink_tables_for_derived(THD *thd)
+static void relink_tables_for_multidelete(THD *thd)
{
if (thd->lex->all_selects_list->next_select_in_list() ||
thd->lex->time_zone_tables_used)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index fcaebe64b43..0da77d5636a 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1131,8 +1131,12 @@ public:
{
return command == COM_PREPARE;
}
- inline gptr trans_alloc(unsigned int size)
- {
+ inline bool fill_derived_tables()
+ {
+ return !only_prepare() && !lex->only_view_structure();
+ }
+ inline gptr trans_alloc(unsigned int size)
+ {
return alloc_root(&transaction.mem_root,size);
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 0923cf811f5..10ef6a081b6 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -25,15 +25,15 @@
#include "sql_select.h"
#include "sql_acl.h"
-static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
- TABLE_LIST *t);
+
/*
- Resolve derived tables in all queries
+ call given derived table processor (preparing or filling tables)
SYNOPSIS
mysql_handle_derived()
lex LEX for this thread
+ processor procedure of derived table processing
RETURN
0 ok
@@ -42,7 +42,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s,
*/
int
-mysql_handle_derived(LEX *lex)
+mysql_handle_derived(LEX *lex, int (*processor)(THD*, LEX*, TABLE_LIST*))
{
if (lex->derived_tables)
{
@@ -55,14 +55,8 @@ mysql_handle_derived(LEX *lex)
cursor= cursor->next_local)
{
int res;
- if (cursor->derived && (res= mysql_derived(lex->thd, lex,
- cursor->derived,
- cursor)))
- {
+ if ((res= (*processor)(lex->thd, lex, cursor)))
return res;
- }
- else if (cursor->ancestor)
- cursor->set_ancestor();
}
if (lex->describe)
{
@@ -80,20 +74,16 @@ mysql_handle_derived(LEX *lex)
/*
- Resolve derived tables in all queries
+ Create temporary table structure (but do not fill it)
SYNOPSIS
mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
thd Thread handle
lex LEX for this thread
- unit node that contains all SELECT's for derived tables
- t TABLE_LIST for the upper SELECT
+ orig_table_list TABLE_LIST for the upper SELECT
IMPLEMENTATION
- Derived table is resolved with temporary table. It is created based on the
- queries defined. After temporary table is created, if this is not EXPLAIN,
- then the entire unit / node is deleted. unit is deleted if UNION is used
- for derived table and node is deleted is it is a simple SELECT.
+ Derived table is resolved with temporary table.
After table creation, the above TABLE_LIST is updated with a new table.
@@ -107,60 +97,126 @@ mysql_handle_derived(LEX *lex)
0 ok
1 Error
-1 Error and error message given
-*/
-
+ */
-static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
- TABLE_LIST *org_table_list)
+int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{
- SELECT_LEX *first_select= unit->first_select();
- TABLE *table;
- int res;
- select_union *derived_result;
- bool is_union= first_select->next_select() &&
- first_select->next_select()->linkage == UNION_TYPE;
- SELECT_LEX *save_current_select= lex->current_select;
- DBUG_ENTER("mysql_derived");
-
- if (!(derived_result= new select_union(0)))
- DBUG_RETURN(1); // out of memory
-
- // st_select_lex_unit::prepare correctly work for single select
- if ((res= unit->prepare(thd, derived_result, 0)))
- goto exit;
-
-
- derived_result->tmp_table_param.init();
- derived_result->tmp_table_param.field_count= unit->types.elements;
- /*
- Temp table is created so that it hounours if UNION without ALL is to be
- processed
- */
- if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
- unit->types, (ORDER*) 0,
- is_union && unit->union_distinct, 1,
- (first_select->options | thd->options |
- TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR,
- org_table_list->alias)))
+ SELECT_LEX_UNIT *unit= orig_table_list->derived;
+ int res= 0;
+ if (unit)
{
- res= -1;
- goto exit;
+ SELECT_LEX *first_select= unit->first_select();
+ TABLE *table= 0;
+ select_union *derived_result;
+ bool is_union= first_select->next_select() &&
+ first_select->next_select()->linkage == UNION_TYPE;
+ DBUG_ENTER("mysql_derived");
+
+ if (!(derived_result= new select_union(0)))
+ DBUG_RETURN(1); // out of memory
+
+ // st_select_lex_unit::prepare correctly work for single select
+ if ((res= unit->prepare(thd, derived_result, 0)))
+ goto exit;
+
+
+ derived_result->tmp_table_param.init();
+ derived_result->tmp_table_param.field_count= unit->types.elements;
+ /*
+ Temp table is created so that it hounours if UNION without ALL is to be
+ processed
+ */
+ if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param,
+ unit->types, (ORDER*) 0,
+ is_union && unit->union_distinct, 1,
+ (first_select->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR,
+ orig_table_list->alias)))
+ {
+ res= -1;
+ goto exit;
+ }
+ derived_result->set_table(table);
+
+exit:
+ /*
+ if it is preparation PS only or commands that need only VIEW structure
+ then we do not need real data and we can skip execution (and parameters
+ is not defined, too)
+ */
+ if (res)
+ {
+ if (table)
+ free_tmp_table(thd, table);
+ delete derived_result;
+ }
+ else
+ {
+ if (!thd->fill_derived_tables())
+ delete derived_result;
+ orig_table_list->derived_result= derived_result;
+ orig_table_list->table= table;
+ orig_table_list->real_name= table->real_name;
+ table->derived_select_number= first_select->select_number;
+ table->tmp_table= TMP_TABLE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ table->grant.privilege= SELECT_ACL;
+#endif
+ orig_table_list->db= (char *)"";
+ // Force read of table stats in the optimizer
+ table->file->info(HA_STATUS_VARIABLE);
+ /* Add new temporary table to list of open derived tables */
+ table->next= thd->derived_tables;
+ thd->derived_tables= table;
+ }
}
- derived_result->set_table(table);
+ else if (orig_table_list->ancestor)
+ orig_table_list->set_ancestor();
+ return (res);
+}
+
- /*
- if it is preparation PS only or commands that need only VIEW structure
- then we do not need real data and we can skip execution (and parameters
- is not defined, too)
+/*
+ fill derived table
+
+ SYNOPSIS
+ mysql_derived_filling()
+ thd Thread handle
+ lex LEX for this thread
+ unit node that contains all SELECT's for derived tables
+ orig_table_list TABLE_LIST for the upper SELECT
+
+ IMPLEMENTATION
+ Derived table is resolved with temporary table. It is created based on the
+ queries defined. After temporary table is filled, if this is not EXPLAIN,
+ then the entire unit / node is deleted. unit is deleted if UNION is used
+ for derived table and node is deleted is it is a simple SELECT.
+
+ RETURN
+ 0 ok
+ 1 Error
+ -1 Error and error message given
*/
- if (!thd->only_prepare() && !lex->only_view_structure())
+
+int mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
+{
+ TABLE *table= orig_table_list->table;
+ SELECT_LEX_UNIT *unit= orig_table_list->derived;
+ int res= 0;
+
+ /*check that table creation pass without problem and it is derived table */
+ if (table && unit)
{
+ SELECT_LEX *first_select= unit->first_select();
+ select_union *derived_result= orig_table_list->derived_result;
+ SELECT_LEX *save_current_select= lex->current_select;
+ bool is_union= first_select->next_select() &&
+ first_select->next_select()->linkage == UNION_TYPE;
if (is_union)
{
// execute union without clean up
- if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK)))
- res= unit->exec();
+ res= unit->exec();
}
else
{
@@ -173,7 +229,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
first_select->options&= ~OPTION_FOUND_ROWS;
lex->current_select= first_select;
- res= mysql_select(thd, &first_select->ref_pointer_array,
+ res= mysql_select(thd, &first_select->ref_pointer_array,
(TABLE_LIST*) first_select->table_list.first,
first_select->with_wild,
first_select->item_list, first_select->where,
@@ -186,49 +242,27 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
SELECT_NO_UNLOCK),
derived_result, unit, first_select);
}
- }
- if (!res)
- {
- /*
- Here we entirely fix both TABLE_LIST and list of SELECT's as
- there were no derived tables
- */
- if (derived_result->flush())
- res= 1;
- else
+ if (!res)
{
- org_table_list->real_name= table->real_name;
- org_table_list->table= table;
- table->derived_select_number= first_select->select_number;
- table->tmp_table= TMP_TABLE;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- table->grant.privilege= SELECT_ACL;
-#endif
- org_table_list->db= (char *)"";
- // Force read of table stats in the optimizer
- table->file->info(HA_STATUS_VARIABLE);
- }
+ /*
+ Here we entirely fix both TABLE_LIST and list of SELECT's as
+ there were no derived tables
+ */
+ if (derived_result->flush())
+ res= 1;
- if (!lex->describe)
- unit->cleanup();
- if (res)
- free_tmp_table(thd, table);
+ if (!lex->describe)
+ unit->cleanup();
+ }
else
{
- /* Add new temporary table to list of open derived tables */
- table->next= thd->derived_tables;
- thd->derived_tables= table;
+ free_tmp_table(thd, table);
+ unit->cleanup();
}
+ lex->current_select= save_current_select;
+ if (res)
+ free_tmp_table(thd, table);
}
- else
- {
- free_tmp_table(thd, table);
- unit->cleanup();
- }
-
-exit:
- delete derived_result;
- lex->current_select= save_current_select;
- DBUG_RETURN(res);
+ return res;
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d978cc14f64..3cbfd96b6aa 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -176,6 +176,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->sphead= NULL;
lex->spcont= NULL;
lex->trg_table= NULL;
+ lex->proc_list.first= 0;
extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
hash_free(&lex->spfuns);
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 1735da6b717..9c2a025e089 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -91,7 +91,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
int error;
String *field_term=ex->field_term,*escaped=ex->escaped;
String *enclosed=ex->enclosed;
- Item *unused_conds;
+ Item *unused_conds= 0;
bool is_fifo=0;
#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 60f69b578e9..5c83a746f73 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4472,7 +4472,6 @@ mysql_init_select(LEX *lex)
{
DBUG_ASSERT(lex->result == 0);
lex->exchange= 0;
- lex->proc_list.first= 0;
}
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index bb2362dd562..212375c8e44 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1314,7 +1314,11 @@ static int mysql_test_multiupdate(Prepared_statement *stmt,
int res;
if ((res= multi_update_precheck(stmt->thd, tables)))
return res;
- return select_like_statement_test(stmt, tables, &mysql_multi_update_prepare);
+ /*
+ here we do not pass tables for opening, tables will be opened and locked
+ by mysql_multi_update_prepare
+ */
+ return select_like_statement_test(stmt, 0, &mysql_multi_update_prepare);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 5e91e730079..46b7f0252e8 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -578,10 +578,17 @@ int mysql_multi_update_prepare(THD *thd)
TABLE_LIST *table_list= lex->query_tables;
List<Item> *fields= &lex->select_lex.item_list;
TABLE_LIST *tl;
- table_map tables_for_update= 0, readonly_tables= 0;
+ table_map tables_for_update;
int res;
bool update_view= 0;
+ uint table_count;
+ const bool using_lock_tables= thd->locked_tables != 0;
DBUG_ENTER("mysql_multi_update_prepare");
+
+ /* open tables and create derived ones, but do not lock and fill them */
+ if (open_tables(thd, table_list, & table_count) ||
+ mysql_handle_derived(lex, &mysql_derived_prepare))
+ DBUG_RETURN(thd->net.report_error ? -1 : 1);
/*
Ensure that we have update privilege for all tables and columns in the
SET part
@@ -606,9 +613,9 @@ int mysql_multi_update_prepare(THD *thd)
call in setup_tables()).
*/
if (setup_tables(thd, table_list, &lex->select_lex.where) ||
- (thd->lex->select_lex.no_wrap_view_item= 1,
+ (lex->select_lex.no_wrap_view_item= 1,
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
- thd->lex->select_lex.no_wrap_view_item= 0,
+ lex->select_lex.no_wrap_view_item= 0,
res))
DBUG_RETURN(-1);
@@ -626,18 +633,10 @@ int mysql_multi_update_prepare(THD *thd)
DBUG_RETURN(-1);
}
- {
- // Find tables used in items
- List_iterator_fast<Item> it(*fields);
- Item *item;
- while ((item= it++))
- {
- tables_for_update|= item->used_tables();
- }
- }
+ tables_for_update= get_table_map(fields);
/*
- Count tables and setup timestamp handling
+ Setup timestamp handling and locking mode
*/
for (tl= table_list; tl ; tl= tl->next_local)
{
@@ -651,22 +650,43 @@ int mysql_multi_update_prepare(THD *thd)
table->timestamp_field->query_id == thd->query_id)
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
- if (!tl->updatable || check_key_in_view(thd, tl))
- readonly_tables|= table->map;
- }
- if (tables_for_update & readonly_tables)
- {
- // find readonly table/view which cause error
- for (tl= table_list; tl ; tl= tl->next_local)
+ /* if table will be updated then check that it is unique */
+ if (table->map & tables_for_update)
{
- if ((readonly_tables & tl->table->map) &&
- (tables_for_update & tl->table->map))
+ if (!tl->updatable || check_key_in_view(thd, tl))
{
- my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
- DBUG_RETURN(-1);
+ my_error(ER_NON_UPDATABLE_TABLE, MYF(0), tl->alias, "UPDATE");
+ DBUG_RETURN(-1);
}
+
+ /*
+ Multi-update can't be constructed over-union => we always have
+ single SELECT on top and have to check underlaying SELECTs of it
+ */
+ if (lex->select_lex.check_updateable_in_subqueries(tl->db,
+ tl->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), tl->real_name);
+ DBUG_RETURN(-1);
+ }
+ DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
+ tl->lock_type= lex->multi_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 (!using_lock_tables)
+ tl->table->reginfo.lock_type= tl->lock_type;
}
+ /* now lock and fill tables */
+ if (lock_tables(thd, table_list, table_count) ||
+ (thd->fill_derived_tables() &&
+ mysql_handle_derived(lex, &mysql_derived_filling)))
+ DBUG_RETURN(thd->net.report_error ? -1 : 1);
DBUG_RETURN (0);
}
@@ -688,11 +708,6 @@ int mysql_multi_update(THD *thd,
multi_update *result;
DBUG_ENTER("mysql_multi_update");
- /* QQ: This should be fixed soon to get lower granularity locks */
- select_lex->set_lock_for_tables(thd->lex->multi_lock_option);
- if ((res= open_and_lock_tables(thd, table_list)))
- DBUG_RETURN(res);
-
if ((res= mysql_multi_update_prepare(thd)))
DBUG_RETURN(res);
diff --git a/sql/table.h b/sql/table.h
index d5bbd0ac2e2..0250d713a56 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -222,6 +222,7 @@ struct st_table {
#define VIEW_CHECK_SKIP 2
struct st_lex;
+struct select_union;
typedef struct st_table_list
{
@@ -238,6 +239,11 @@ typedef struct st_table_list
List<String> *use_index, *ignore_index;
TABLE *table; /* opened table */
/*
+ select_result for derived table to pass it from table creation to table
+ filling procedure
+ */
+ select_union *derived_result;
+ /*
Reference from aux_tables to local list entry of main select of
multi-delete statement:
delete t1 from t2,t1 where t1.a<'B' and t2.b=t1.b;