new lock for multiupdate:
- open and create derived tables - detect which tables should be locked for write - lock and fill derived tables some unitialized variables fixed mysql-test/r/lock_multi.result: correct results returned mysql-test/r/multi_update.result: correct results returned mysql-test/r/view.result: correct results returned mysql-test/t/multi_update.test: correct results returned mysql-test/t/view.test: correct results returned sql/mysql_priv.h: derived tables processing splited on table creation and table filling sql/sql_base.cc: derived tables processing splited on table creation and table filling sql/sql_class.h: function to detect when we need fill derived tables sql/sql_derived.cc: derived tables processing splited on table creation and table filling sql/sql_lex.cc: fixed uninitialized value sql/sql_load.cc: fixed uninitialized value sql/sql_parse.cc: initialization muved (will be done for all queries) sql/sql_prepare.cc: preparation of multiupdate changed a bit because new locking procedure sql/sql_update.cc: new lock for multiupdate: - open and create derived tables - detect which tables should be locked for write - lock and fill derived tables sql/table.h: place to store select_result between creation and filling tables
This commit is contained in:
parent
e981c83610
commit
8b0ece5e88
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)))
|
||||
@ -1859,19 +1860,21 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
||||
uint 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)
|
||||
|
@ -1131,6 +1131,10 @@ public:
|
||||
{
|
||||
return command == COM_PREPARE;
|
||||
}
|
||||
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);
|
||||
|
@ -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,15 +55,9 @@ 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.
|
||||
|
||||
@ -109,17 +99,17 @@ mysql_handle_derived(LEX *lex)
|
||||
-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_UNIT *unit= orig_table_list->derived;
|
||||
int res= 0;
|
||||
if (unit)
|
||||
{
|
||||
SELECT_LEX *first_select= unit->first_select();
|
||||
TABLE *table;
|
||||
int res;
|
||||
TABLE *table= 0;
|
||||
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)))
|
||||
@ -142,24 +132,90 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
(first_select->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
HA_POS_ERROR,
|
||||
org_table_list->alias)))
|
||||
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 (!thd->only_prepare() && !lex->only_view_structure())
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (orig_table_list->ancestor)
|
||||
orig_table_list->set_ancestor();
|
||||
return (res);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
else
|
||||
@ -186,7 +242,6 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
SELECT_NO_UNLOCK),
|
||||
derived_result, unit, first_select);
|
||||
}
|
||||
}
|
||||
|
||||
if (!res)
|
||||
{
|
||||
@ -196,39 +251,18 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
|
||||
*/
|
||||
if (derived_result->flush())
|
||||
res= 1;
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (!lex->describe)
|
||||
unit->cleanup();
|
||||
if (res)
|
||||
free_tmp_table(thd, table);
|
||||
else
|
||||
{
|
||||
/* Add new temporary table to list of open derived tables */
|
||||
table->next= thd->derived_tables;
|
||||
thd->derived_tables= table;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free_tmp_table(thd, table);
|
||||
unit->cleanup();
|
||||
}
|
||||
|
||||
exit:
|
||||
delete derived_result;
|
||||
lex->current_select= save_current_select;
|
||||
DBUG_RETURN(res);
|
||||
if (res)
|
||||
free_tmp_table(thd, table);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -4472,7 +4472,6 @@ mysql_init_select(LEX *lex)
|
||||
{
|
||||
DBUG_ASSERT(lex->result == 0);
|
||||
lex->exchange= 0;
|
||||
lex->proc_list.first= 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 table will be updated then check that it is unique */
|
||||
if (table->map & tables_for_update)
|
||||
{
|
||||
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 ((readonly_tables & tl->table->map) &&
|
||||
(tables_for_update & tl->table->map))
|
||||
{
|
||||
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);
|
||||
|
||||
|
@ -222,6 +222,7 @@ struct st_table {
|
||||
#define VIEW_CHECK_SKIP 2
|
||||
|
||||
struct st_lex;
|
||||
struct select_union;
|
||||
|
||||
typedef struct st_table_list
|
||||
{
|
||||
@ -237,6 +238,11 @@ typedef struct st_table_list
|
||||
/* ... join ... USE INDEX ... IGNORE INDEX */
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user