1
0
mirror of https://github.com/MariaDB/server.git synced 2025-06-23 19:21:55 +03:00
sql/item.cc:
  Auto merged
sql/item.h:
  Auto merged
sql/item_cmpfunc.h:
  Auto merged
sql/item_subselect.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/opt_sum.cc:
  Auto merged
sql/sp.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_help.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_load.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_view.h:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
This commit is contained in:
unknown
2004-11-21 20:08:12 +02:00
52 changed files with 1333 additions and 306 deletions

View File

@ -409,4 +409,7 @@
#define ER_PS_MANY_PARAM 1390 #define ER_PS_MANY_PARAM 1390
#define ER_KEY_PART_0 1391 #define ER_KEY_PART_0 1391
#define ER_VIEW_CHECKSUM 1392 #define ER_VIEW_CHECKSUM 1392
#define ER_ERROR_MESSAGES 393 #define ER_VIEW_MULTIUPDATE 1393
#define ER_VIEW_NO_INSERT_FIELD_LIST 1394
#define ER_VIEW_DELETE_MERGE_VIEW 1395
#define ER_ERROR_MESSAGES 396

View File

@ -887,7 +887,7 @@ insert into t1 values (1), (2), (3), (200);
create view v1 (x) as select a from t1 where a > 1; create view v1 (x) as select a from t1 where a > 1;
create view v2 (y) as select x from v1 where x < 100; create view v2 (y) as select x from v1 where x < 100;
select * from v2; select * from v2;
x y
2 2
3 3
drop table t1; drop table t1;
@ -1661,3 +1661,199 @@ check table v1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.v1 check error View 'test.v1' references invalid table(s) or column(s) test.v1 check error View 'test.v1' references invalid table(s) or column(s)
drop view v1; drop view v1;
create table t2 (a int);
create table t3 (a int);
insert into t1 values (1), (2), (3);
insert into t2 values (1), (3);
insert into t3 values (1), (2), (4);
create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
select * from t3 left join v3 on (t3.a = v3.a);
a a b
1 1 1
2 2 NULL
4 NULL NULL
explain extended select * from t3 left join v3 on (t3.a = v3.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join `test`.`t2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
create view v1 (a) as select a from t1;
create view v2 (a) as select a from t2;
create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
select * from t3 left join v4 on (t3.a = v4.a);
a a b
1 1 1
2 2 NULL
4 NULL NULL
explain extended select * from t3 left join v4 on (t3.a = v4.a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 3
1 PRIMARY t1 ALL NULL NULL NULL NULL 3
1 PRIMARY t2 ALL NULL NULL NULL NULL 2
Warnings:
Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`v1` left join `test`.`v2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1
prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
execute stmt1;
a a b
1 1 1
2 2 NULL
4 NULL NULL
execute stmt1;
a a b
1 1 1
2 2 NULL
4 NULL NULL
deallocate prepare stmt1;
drop view v4,v3,v2,v1;
drop tables t1,t2,t3;
create table t1 (a int, primary key (a), b int);
create table t2 (a int, primary key (a));
insert into t1 values (1,100), (2,200);
insert into t2 values (1), (3);
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
update v3 set a= 10 where a=1;
select * from t1;
a b
10 100
2 200
select * from t2;
a
1
3
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
update v2 set a= 10 where a=200;
ERROR HY000: The target table v2 of the UPDATE is not updatable
select * from v3;
a b
2 1
10 1
2 3
10 3
select * from v2;
a b
100 1
200 1
100 3
200 3
set @a= 10;
set @b= 100;
prepare stmt1 from "update v3 set a= ? where a=?";
execute stmt1 using @a,@b;
select * from v3;
a b
2 1
10 1
2 3
10 3
set @a= 300;
set @b= 10;
execute stmt1 using @a,@b;
select * from v3;
a b
2 1
300 1
2 3
300 3
deallocate prepare stmt1;
drop view v3,v2;
drop tables t1,t2;
create table t1 (a int, primary key (a), b int);
create table t2 (a int, primary key (a), b int);
insert into t2 values (1000, 2000);
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
insert into v3 values (1,2);
ERROR HY000: Can not insert into join view 'test.v3' without fields list
insert into v3 select * from t2;
ERROR HY000: Can not insert into join view 'test.v3' without fields list
insert into v3(a,b) values (1,2);
ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
insert into v3(a,b) select * from t2;
ERROR HY000: Can not modify more than one base table through a join view 'test.v3'
insert into v3(a) values (1);
insert into v3(b) values (10);
insert into v3(a) select a from t2;
insert into v3(b) select b from t2;
Warnings:
Warning 1263 Column set to default value; NULL supplied to NOT NULL column 'a' at row 2
insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
select * from t1;
a b
10002 NULL
10 NULL
1000 NULL
select * from t2;
a b
1000 2000
10 NULL
2000 NULL
0 NULL
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
insert into v2(a) values (10);
ERROR HY000: The target table v2 of the INSERT is not updatable
select * from v3;
a b
10 1000
1000 1000
10002 1000
10 10
1000 10
10002 10
10 2000
1000 2000
10002 2000
10 0
1000 0
10002 0
select * from v2;
a b
NULL 1000
NULL 1000
NULL 1000
NULL 10
NULL 10
NULL 10
NULL 2000
NULL 2000
NULL 2000
NULL 0
NULL 0
NULL 0
delete from v3;
ERROR HY000: Can not delete from join view 'test.v3'
delete v3,t1 from v3,t1;
ERROR HY000: Can not delete from join view 'test.v3'
delete from t1;
prepare stmt1 from "insert into v3(a) values (?);";
set @a= 100;
execute stmt1 using @a;
set @a= 300;
execute stmt1 using @a;
deallocate prepare stmt1;
prepare stmt1 from "insert into v3(a) select ?;";
set @a= 101;
execute stmt1 using @a;
set @a= 301;
execute stmt1 using @a;
deallocate prepare stmt1;
select * from v3;
a b
100 1000
101 1000
300 1000
301 1000
100 10
101 10
300 10
301 10
100 2000
101 2000
300 2000
301 2000
100 0
101 0
300 0
301 0
drop view v3,v2;
drop tables t1,t2;

View File

@ -1599,3 +1599,120 @@ check table v1,t1;
drop table t1; drop table t1;
check table v1; check table v1;
drop view v1; drop view v1;
#
# merge of VIEW with several tables
#
create table t1 (a int);
create table t2 (a int);
create table t3 (a int);
insert into t1 values (1), (2), (3);
insert into t2 values (1), (3);
insert into t3 values (1), (2), (4);
# view over tables
create view v3 (a,b) as select t1.a as a, t2.a as b from t1 left join t2 on (t1.a=t2.a);
select * from t3 left join v3 on (t3.a = v3.a);
explain extended select * from t3 left join v3 on (t3.a = v3.a);
# view over views
create view v1 (a) as select a from t1;
create view v2 (a) as select a from t2;
create view v4 (a,b) as select v1.a as a, v2.a as b from v1 left join v2 on (v1.a=v2.a);
select * from t3 left join v4 on (t3.a = v4.a);
explain extended select * from t3 left join v4 on (t3.a = v4.a);
# PS with view over views
prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
drop view v4,v3,v2,v1;
drop tables t1,t2,t3;
#
# updating of join view
#
create table t1 (a int, primary key (a), b int);
create table t2 (a int, primary key (a));
insert into t1 values (1,100), (2,200);
insert into t2 values (1), (3);
# legal view for update
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
update v3 set a= 10 where a=1;
select * from t1;
select * from t2;
# view without primary key
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
-- error 1288
update v2 set a= 10 where a=200;
# just view selects
select * from v3;
select * from v2;
# prepare statement with updating join view
set @a= 10;
set @b= 100;
prepare stmt1 from "update v3 set a= ? where a=?";
execute stmt1 using @a,@b;
select * from v3;
set @a= 300;
set @b= 10;
execute stmt1 using @a,@b;
select * from v3;
deallocate prepare stmt1;
drop view v3,v2;
drop tables t1,t2;
#
# inserting/deleting join view
#
create table t1 (a int, primary key (a), b int);
create table t2 (a int, primary key (a), b int);
insert into t2 values (1000, 2000);
create view v3 (a,b) as select t1.a as a, t2.a as b from t1, t2;
# inserting into join view without field list
-- error 1365
insert into v3 values (1,2);
-- error 1365
insert into v3 select * from t2;
# inserting in several tables of join view
-- error 1364
insert into v3(a,b) values (1,2);
-- error 1364
insert into v3(a,b) select * from t2;
# correct inserts into join view
insert into v3(a) values (1);
insert into v3(b) values (10);
insert into v3(a) select a from t2;
insert into v3(b) select b from t2;
insert into v3(a) values (1) on duplicate key update a=a+10000+VALUES(a);
select * from t1;
select * from t2;
# view without primary key
create view v2 (a,b) as select t1.b as a, t2.a as b from t1, t2;
-- error 1288
insert into v2(a) values (10);
# just view selects
select * from v3;
select * from v2;
# try delete from join view
-- error 1366
delete from v3;
-- error 1366
delete v3,t1 from v3,t1;
# delete from t1 just to reduce result set size
delete from t1;
# prepare statement with insert join view
prepare stmt1 from "insert into v3(a) values (?);";
set @a= 100;
execute stmt1 using @a;
set @a= 300;
execute stmt1 using @a;
deallocate prepare stmt1;
prepare stmt1 from "insert into v3(a) select ?;";
set @a= 101;
execute stmt1 using @a;
set @a= 301;
execute stmt1 using @a;
deallocate prepare stmt1;
select * from v3;
drop view v3,v2;
drop tables t1,t2;

View File

@ -46,12 +46,11 @@ void item_init(void)
} }
Item::Item(): Item::Item():
name_length(0), fixed(0), name(0), orig_name(0), name_length(0), fixed(0),
collation(default_charset(), DERIVATION_COERCIBLE) collation(default_charset(), DERIVATION_COERCIBLE)
{ {
marker= 0; marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0; maybe_null=null_value=with_sum_func=unsigned_flag=0;
name= 0;
decimals= 0; max_length= 0; decimals= 0; max_length= 0;
/* Put item in free list so that we can free all items at end */ /* Put item in free list so that we can free all items at end */
@ -81,6 +80,7 @@ Item::Item():
Item::Item(THD *thd, Item *item): Item::Item(THD *thd, Item *item):
str_value(item->str_value), str_value(item->str_value),
name(item->name), name(item->name),
orig_name(item->orig_name),
max_length(item->max_length), max_length(item->max_length),
marker(item->marker), marker(item->marker),
decimals(item->decimals), decimals(item->decimals),
@ -111,10 +111,12 @@ void Item::print_item_w_name(String *str)
void Item::cleanup() void Item::cleanup()
{ {
DBUG_ENTER("Item::cleanup"); DBUG_ENTER("Item::cleanup");
DBUG_PRINT("info", ("Item: 0x%lx", this)); DBUG_PRINT("info", ("Item: 0x%lx, Type: %d, name %s, original name %s",
DBUG_PRINT("info", ("Type: %d", (int)type())); this, (int)type(), name, orig_name));
fixed=0; fixed=0;
marker= 0; marker= 0;
if (orig_name)
name= orig_name;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -135,6 +137,26 @@ bool Item::cleanup_processor(byte *arg)
} }
/*
rename item (used for views, cleanup() return original name)
SYNOPSIS
Item::rename()
new_name new name of item;
*/
void Item::rename(char *new_name)
{
/*
we can compare pointers to names here, bacause if name was not changed,
pointer will be same
*/
if (!orig_name && new_name != name)
orig_name= name;
name= new_name;
}
Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par) const char *field_name_par)
:orig_db_name(db_name_par), orig_table_name(table_name_par), :orig_db_name(db_name_par), orig_table_name(table_name_par),

View File

@ -139,6 +139,8 @@ public:
*/ */
String str_value; String str_value;
my_string name; /* Name from select */ my_string name; /* Name from select */
/* Original item name (if it was renamed)*/
my_string orig_name;
Item *next; Item *next;
uint32 max_length; uint32 max_length;
uint name_length; /* Length of name */ uint name_length; /* Length of name */
@ -166,6 +168,7 @@ public:
name=0; name=0;
} /*lint -e1509 */ } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs); void set_name(const char *str,uint length, CHARSET_INFO *cs);
void rename(char *new_name);
void init_make_field(Send_field *tmp_field,enum enum_field_types type); void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup(); virtual void cleanup();
virtual void make_field(Send_field *field); virtual void make_field(Send_field *field);

View File

@ -959,7 +959,8 @@ public:
void update_used_tables(); void update_used_tables();
void print(String *str); void print(String *str);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields); void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
void top_level_item() { abort_on_null=1; } void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item); void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);

View File

@ -1422,7 +1422,7 @@ void subselect_uniquesubquery_engine::exclude()
table_map subselect_engine::calc_const_tables(TABLE_LIST *table) table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
{ {
table_map map= 0; table_map map= 0;
for(; table; table= table->next_local) for(; table; table= table->next_leaf)
{ {
TABLE *tbl= table->table; TABLE *tbl= table->table;
if (tbl && tbl->const_table) if (tbl && tbl->const_table)
@ -1435,14 +1435,13 @@ table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
table_map subselect_single_select_engine::upper_select_const_tables() table_map subselect_single_select_engine::upper_select_const_tables()
{ {
return calc_const_tables((TABLE_LIST *) select_lex->outer_select()-> return calc_const_tables((TABLE_LIST *) select_lex->outer_select()->
table_list.first); leaf_tables);
} }
table_map subselect_union_engine::upper_select_const_tables() table_map subselect_union_engine::upper_select_const_tables()
{ {
return calc_const_tables((TABLE_LIST *) unit->outer_select()-> return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables);
table_list.first);
} }

View File

@ -668,7 +668,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
uint length, Item **ref, uint length, Item **ref,
bool check_grants_table, bool check_grants_view, bool check_grants_table, bool check_grants_view,
bool allow_rowid, bool allow_rowid,
uint *cached_field_index_ptr); uint *cached_field_index_ptr,
bool register_tree_change);
Field * Field *
find_field_in_real_table(THD *thd, TABLE *table, const char *name, find_field_in_real_table(THD *thd, TABLE *table, const char *name,
uint length, bool check_grants, bool allow_rowid, uint length, bool check_grants, bool allow_rowid,
@ -800,13 +801,15 @@ bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name, const char *db_name, const char *table_name,
List_iterator<Item> *it, bool any_privileges, List_iterator<Item> *it, bool any_privileges,
bool allocate_view_names); bool allocate_view_names);
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds); bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
TABLE_LIST **leaves, bool refresh_only);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num); List<Item> *sum_func_list, uint wild_num);
bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
List<Item> &item, bool set_query_id, List<Item> &item, bool set_query_id,
List<Item> *sum_func_list, bool allow_sum_func); List<Item> *sum_func_list, bool allow_sum_func);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
int setup_ftfuncs(SELECT_LEX* select); int setup_ftfuncs(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd); void wait_for_refresh(THD *thd);

View File

@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
SYNOPSIS SYNOPSIS
opt_sum_query() opt_sum_query()
tables Tables in query tables list of leaves of join table tree
all_fields All fields to be returned all_fields All fields to be returned
conds WHERE clause conds WHERE clause
NOTE: NOTE:
This function is only called for queries with sum functions and no This function is only called for queries with sum functions and no
@ -89,7 +89,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
where_tables= conds->used_tables(); where_tables= conds->used_tables();
/* Don't replace expression on a table that is part of an outer join */ /* Don't replace expression on a table that is part of an outer join */
for (TABLE_LIST *tl= tables; tl; tl= tl->next_local) for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
{ {
if (tl->on_expr) if (tl->on_expr)
{ {
@ -128,7 +128,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
{ {
longlong count= 1; longlong count= 1;
TABLE_LIST *table; TABLE_LIST *table;
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_leaf)
{ {
if (outer_tables || (table->table->file->table_flags() & if (outer_tables || (table->table->file->table_flags() &
HA_NOT_EXACT_COUNT) || table->schema_table) HA_NOT_EXACT_COUNT) || table->schema_table)

View File

@ -421,3 +421,6 @@ character-set=latin2
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -412,3 +412,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -421,3 +421,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -414,3 +414,6 @@ character-set=latin7
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -422,3 +422,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=greek
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -414,3 +414,6 @@ character-set=latin2
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -413,3 +413,6 @@ character-set=ujis
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=euckr
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -411,3 +411,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -411,3 +411,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -414,3 +414,6 @@ character-set=latin2
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -411,3 +411,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -414,3 +414,6 @@ character-set=latin2
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -376,7 +376,7 @@ character-set=koi8r
"View SELECT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'" "View SELECT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> '%-.64s'"
"View SELECT <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> view <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" "View SELECT <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> view <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>)" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> view <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><>) <20> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28>)"
"View '%-.64s.%-.64s' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" "View '%-.64s.%-.64s' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"Can't drop a %s from within another stored routine" "Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler" "GOTO is not allowed in a stored procedure handler"
@ -414,3 +414,6 @@ character-set=koi8r
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s'"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s' <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s'"

View File

@ -402,3 +402,6 @@ character-set=cp1250
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -417,3 +417,6 @@ character-set=latin2
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -413,3 +413,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -409,3 +409,6 @@ character-set=latin1
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"View text checksum failed" "View text checksum failed"
"Can not modify more than one base table through a join view '%-.64s.%-.64s'"
"Can not insert into join view '%-.64s.%-.64s' without fields list"
"Can not delete from join view '%-.64s.%-.64s'"

View File

@ -415,3 +415,6 @@ character-set=koi8u
"Prepared statement contains too many placeholders" "Prepared statement contains too many placeholders"
"Key part '%-.64s' length cannot be 0" "Key part '%-.64s' length cannot be 0"
"<22><><EFBFBD><EFBFBD>צ<EFBFBD><D7A6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϧ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>" "<22><><EFBFBD><EFBFBD>צ<EFBFBD><D7A6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϧ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ¦<><C2A6><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> VIEW '%-.64s.%-.64s', <20><> ͦ<>Ԧ<EFBFBD><D4A6> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> VIEW '%-.64s.%-.64s', <20><> ͦ<><CDA6><EFBFBD><EFBFBD><EFBFBD> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>æ<EFBFBD>"
"<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> VIEW '%-.64s.%-.64s', <20><> ͦ<><CDA6><EFBFBD><EFBFBD><EFBFBD> <20><>˦<EFBFBD><CBA6><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"

View File

@ -575,6 +575,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
Item *item; Item *item;
List<Item> field_list; List<Item> field_list;
struct st_used_field *used_field; struct st_used_field *used_field;
TABLE_LIST *leaves= 0;
st_used_field used_fields[array_elements(init_fields)]; st_used_field used_fields[array_elements(init_fields)];
memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields)); memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields));
@ -607,7 +608,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
tables is not VIEW for sure => we can pass 0 as condition tables is not VIEW for sure => we can pass 0 as condition
*/ */
setup_tables(thd, &tables, 0); setup_tables(thd, &tables, 0, &leaves, 0);
for (used_field= &used_fields[0]; for (used_field= &used_fields[0];
used_field->field_name; used_field->field_name;
used_field++) used_field++)

View File

@ -2378,7 +2378,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (!find_field_in_table(thd, table_list, column->column.ptr(), if (!find_field_in_table(thd, table_list, column->column.ptr(),
column->column.ptr(), column->column.ptr(),
column->column.length(), 0, 0, 0, 0, column->column.length(), 0, 0, 0, 0,
&unused_field_idx)) &unused_field_idx, FALSE))
{ {
my_error(ER_BAD_FIELD_ERROR, MYF(0), my_error(ER_BAD_FIELD_ERROR, MYF(0),
column->column.c_ptr(), table_list->alias); column->column.c_ptr(), table_list->alias);

View File

@ -557,10 +557,10 @@ void close_temporary_tables(THD *thd)
SYNOPSIS SYNOPSIS
find_table_in_list() find_table_in_list()
table Pointer to table list table Pointer to table list
offset Offset to which list in table structure to use offset Offset to which list in table structure to use
db_name Data base name db_name Data base name
table_name Table name table_name Table name
NOTES: NOTES:
This is called by find_table_in_local_list() and This is called by find_table_in_local_list() and
@ -580,14 +580,14 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
{ {
for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
{ {
if ((!strcmp(table->db, db_name) && if (table->table->tmp_table == NO_TMP_TABLE &&
!strcmp(table->real_name, table_name)) || ((!strcmp(table->db, db_name) &&
(table->view && !strcmp(table->real_name, table_name)) ||
table->table->table_cache_key && // it is not temporary table (table->view &&
!my_strcasecmp(table_alias_charset, !my_strcasecmp(table_alias_charset,
table->table->table_cache_key, db_name) && table->table->table_cache_key, db_name) &&
!my_strcasecmp(table_alias_charset, !my_strcasecmp(table_alias_charset,
table->table->table_name, table_name))) table->table->table_name, table_name))))
break; break;
} }
} }
@ -595,12 +595,12 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
{ {
for (; table; table= *(TABLE_LIST **) ((char*) table + offset)) for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
{ {
if ((!strcmp(table->db, db_name) && if (table->table->tmp_table == NO_TMP_TABLE &&
!strcmp(table->real_name, table_name)) || ((!strcmp(table->db, db_name) &&
(table->view && // it is VIEW and !strcmp(table->real_name, table_name)) ||
table->table->table_cache_key && // it is not temporary table (table->view &&
!strcmp(table->table->table_cache_key, db_name) && !strcmp(table->table->table_cache_key, db_name) &&
!strcmp(table->table->table_name, table_name))) !strcmp(table->table->table_name, table_name))))
break; break;
} }
} }
@ -2072,6 +2072,8 @@ Field *view_ref_found= (Field*) 0x2;
allow_rowid do allow finding of "_rowid" field? allow_rowid do allow finding of "_rowid" field?
cached_field_index_ptr cached position in field list (used to cached_field_index_ptr cached position in field list (used to
speedup prepared tables field finding) speedup prepared tables field finding)
register_tree_change TRUE if ref is not stack variable and we
need register changes in item tree
RETURN RETURN
0 field is not found 0 field is not found
@ -2085,17 +2087,21 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
uint length, Item **ref, uint length, Item **ref,
bool check_grants_table, bool check_grants_view, bool check_grants_table, bool check_grants_view,
bool allow_rowid, bool allow_rowid,
uint *cached_field_index_ptr) uint *cached_field_index_ptr,
bool register_tree_change)
{ {
DBUG_ENTER("find_field_in_table");
DBUG_PRINT("enter", ("table:%s name: %s item name %s, ref 0x%lx",
table_list->alias, name, item_name, (ulong)ref));
Field *fld; Field *fld;
if (table_list->field_translation) if (table_list->field_translation)
{ {
DBUG_ASSERT(ref != 0 && table_list->view != 0); DBUG_ASSERT(ref != 0 && table_list->view != 0);
uint num= table_list->view->select_lex.item_list.elements; uint num= table_list->view->select_lex.item_list.elements;
Item **trans= table_list->field_translation; Field_translator *trans= table_list->field_translation;
for (uint i= 0; i < num; i ++) for (uint i= 0; i < num; i ++)
{ {
if (strcmp(trans[i]->name, name) == 0) if (strcmp(trans[i].name, name) == 0)
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants_view && if (check_grants_view &&
@ -2103,25 +2109,26 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
table_list->view_db.str, table_list->view_db.str,
table_list->view_name.str, table_list->view_name.str,
name, length)) name, length))
return WRONG_GRANT; DBUG_RETURN(WRONG_GRANT);
#endif #endif
if (thd->lex->current_select->no_wrap_view_item) if (thd->lex->current_select->no_wrap_view_item)
*ref= trans[i]; *ref= trans[i].item;
else else
{ {
Item_ref *item_ref= new Item_ref(trans + i, table_list->view_name.str, Item_ref *item_ref= new Item_ref(&trans[i].item,
table_list->view_name.str,
item_name); item_name);
/* as far as Item_ref have defined reference it do not need tables */ /* as far as Item_ref have defined reference it do not need tables */
if (item_ref) if (register_tree_change && item_ref)
{ {
thd->change_item_tree(ref, item_ref); thd->change_item_tree(ref, item_ref);
(*ref)->fix_fields(thd, 0, ref); (*ref)->fix_fields(thd, 0, ref);
} }
} }
return (Field*) view_ref_found; DBUG_RETURN((Field*) view_ref_found);
} }
} }
return 0; DBUG_RETURN(0);
} }
fld= find_field_in_real_table(thd, table_list->table, name, length, fld= find_field_in_real_table(thd, table_list->table, name, length,
check_grants_table, allow_rowid, check_grants_table, allow_rowid,
@ -2135,10 +2142,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
table_list->view_name.str, table_list->view_name.str,
name, length)) name, length))
{ {
return WRONG_GRANT; DBUG_RETURN(WRONG_GRANT);
} }
#endif #endif
return fld; DBUG_RETURN(fld);
} }
@ -2274,17 +2281,34 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
field makes some prepared query ambiguous and so erroneous, but we field makes some prepared query ambiguous and so erroneous, but we
accept this trade off. accept this trade off.
*/ */
found= find_field_in_real_table(thd, item->cached_table->table, if (item->cached_table->table)
name, length, {
test(item->cached_table-> found= find_field_in_real_table(thd, item->cached_table->table,
table->grant.want_privilege) && name, length,
check_privileges, test(item->cached_table->
1, &(item->cached_field_index)); table->grant.want_privilege) &&
check_privileges,
1, &(item->cached_field_index));
}
else
{
TABLE_LIST *table= item->cached_table;
Field *find= find_field_in_table(thd, table, name, item->name, length,
ref,
(table->table &&
test(table->table->grant.
want_privilege) &&
check_privileges),
(test(table->grant.want_privilege) &&
check_privileges),
1, &(item->cached_field_index),
TRUE);
}
if (found) if (found)
{ {
if (found == WRONG_GRANT) if (found == WRONG_GRANT)
return (Field*) 0; return (Field*) 0;
return found; return found;
} }
} }
@ -2312,12 +2336,14 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
found_table=1; found_table=1;
Field *find= find_field_in_table(thd, tables, name, item->name, Field *find= find_field_in_table(thd, tables, name, item->name,
length, ref, length, ref,
(test(tables->table->grant. (tables->table &&
test(tables->table->grant.
want_privilege) && want_privilege) &&
check_privileges), check_privileges),
(test(tables->grant.want_privilege) && (test(tables->grant.want_privilege) &&
check_privileges), check_privileges),
1, &(item->cached_field_index)); 1, &(item->cached_field_index),
TRUE);
if (find) if (find)
{ {
item->cached_table= tables; item->cached_table= tables;
@ -2368,7 +2394,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
bool allow_rowid= tables && !tables->next_local; // Only one table bool allow_rowid= tables && !tables->next_local; // Only one table
for (; tables ; tables= tables->next_local) for (; tables ; tables= tables->next_local)
{ {
if (!tables->table) if (!tables->table && !tables->ancestor)
{ {
if (report_error == REPORT_ALL_ERRORS || if (report_error == REPORT_ALL_ERRORS ||
report_error == REPORT_EXCEPT_NON_UNIQUE) report_error == REPORT_EXCEPT_NON_UNIQUE)
@ -2378,12 +2404,15 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
Field *field= find_field_in_table(thd, tables, name, item->name, Field *field= find_field_in_table(thd, tables, name, item->name,
length, ref, length, ref,
(test(tables->table->grant. (tables->table &&
test(tables->table->grant.
want_privilege) && want_privilege) &&
check_privileges), check_privileges),
(test(tables->grant.want_privilege) && (test(tables->grant.want_privilege) &&
check_privileges), check_privileges),
allow_rowid, &(item->cached_field_index)); allow_rowid,
&(item->cached_field_index),
TRUE);
if (field) if (field)
{ {
if (field == WRONG_GRANT) if (field == WRONG_GRANT)
@ -2709,7 +2738,6 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
if (!item->fixed && item->fix_fields(thd, tables, it.ref()) || if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1)) (item= *(it.ref()))->check_cols(1))
{ {
select_lex->no_wrap_view_item= 0;
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
} }
if (ref) if (ref)
@ -2723,6 +2751,36 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
} }
/*
make list of leaves of join table tree
SYNOPSIS
make_leaves_list()
list pointer to pointer on list first element
tables table list
RETURN pointer on pointer to next_leaf of last element
*/
TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables)
{
for (TABLE_LIST *table= tables; table; table= table->next_local)
{
if (table->view && !table->table)
{
/* it is for multi table views only, check it */
DBUG_ASSERT(table->ancestor->next_local);
list= make_leaves_list(list, table->ancestor);
}
else
{
*list= table;
list= &table->next_leaf;
}
}
return list;
}
/* /*
prepare tables prepare tables
@ -2731,11 +2789,14 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
thd Thread handler thd Thread handler
tables Table list tables Table list
conds Condition of current SELECT (can be changed by VIEW) conds Condition of current SELECT (can be changed by VIEW)
leaves List of join table leaves list
refresh It is onle refresh for subquery
NOTE NOTE
Remap table numbers if INSERT ... SELECT Remap table numbers if INSERT ... SELECT
Check also that the 'used keys' and 'ignored keys' exists and set up the Check also that the 'used keys' and 'ignored keys' exists and set up the
table structure accordingly table structure accordingly
Create leaf tables list
This has to be called for all tables that are used by items, as otherwise This has to be called for all tables that are used by items, as otherwise
table->map is not set and all Item_field will be regarded as const items. table->map is not set and all Item_field will be regarded as const items.
@ -2745,16 +2806,23 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
1 error 1 error
*/ */
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds) bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
TABLE_LIST **leaves, bool refresh)
{ {
DBUG_ENTER("setup_tables"); DBUG_ENTER("setup_tables");
if (!tables || tables->setup_is_done) if (!tables || tables->setup_is_done)
DBUG_RETURN(0); DBUG_RETURN(0);
tables->setup_is_done= 1; tables->setup_is_done= 1;
if (!(*leaves))
{
make_leaves_list(leaves, tables);
}
uint tablenr=0; uint tablenr=0;
for (TABLE_LIST *table_list= tables; for (TABLE_LIST *table_list= *leaves;
table_list; table_list;
table_list= table_list->next_local, tablenr++) table_list= table_list->next_leaf, tablenr++)
{ {
TABLE *table= table_list->table; TABLE *table= table_list->table;
setup_table_map(table, table_list, tablenr); setup_table_map(table, table_list, tablenr);
@ -2776,16 +2844,24 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds)
table->keys_in_use_for_query.subtract(map); table->keys_in_use_for_query.subtract(map);
} }
table->used_keys.intersect(table->keys_in_use_for_query); table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->ancestor &&
table_list->setup_ancestor(thd, conds,
table_list->effective_with_check))
DBUG_RETURN(1);
} }
if (tablenr > MAX_TABLES) if (tablenr > MAX_TABLES)
{ {
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES); my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (!refresh)
{
for (TABLE_LIST *table_list= tables;
table_list;
table_list= table_list->next_local)
{
if (table_list->ancestor &&
table_list->setup_ancestor(thd, conds,
table_list->effective_with_check))
DBUG_RETURN(1);
}
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -2889,9 +2965,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
tables->alias) && tables->alias) &&
(!db_name || !strcmp(tables->db,db_name)))) (!db_name || !strcmp(tables->db,db_name))))
{ {
bool view;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access right to all columns */ /* Ensure that we have access right to all columns */
if (!(table->grant.privilege & SELECT_ACL) && !any_privileges) if (!((table && (table->grant.privilege & SELECT_ACL) ||
tables->view && (tables->grant.privilege & SELECT_ACL))) &&
!any_privileges)
{ {
if (tables->view) if (tables->view)
{ {
@ -2904,6 +2983,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
} }
else if (!tables->schema_table) else if (!tables->schema_table)
{ {
DBUG_ASSERT(table != 0);
table_iter.set(tables); table_iter.set(tables);
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant, if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
table->table_cache_key, table->real_name, table->table_cache_key, table->real_name,
@ -2912,8 +2992,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
} }
} }
#endif #endif
if (table)
thd->used_tables|= table->map;
else
{
view_iter.set(tables);
for (; !view_iter.end_of_fields(); view_iter.next())
{
thd->used_tables|= view_iter.item(thd)->used_tables();
}
}
natural_join_table= 0; natural_join_table= 0;
thd->used_tables|= table->map;
last= embedded= tables; last= embedded= tables;
while ((embedding= embedded->embedding) && while ((embedding= embedded->embedding) &&
@ -2940,9 +3029,15 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
natural_join_table= embedding; natural_join_table= embedding;
} }
if (tables->field_translation) if (tables->field_translation)
{
iterator= &view_iter; iterator= &view_iter;
view= 1;
}
else else
{
iterator= &table_iter; iterator= &table_iter;
view= 0;
}
iterator->set(tables); iterator->set(tables);
for (; !iterator->end_of_fields(); iterator->next()) for (; !iterator->end_of_fields(); iterator->next())
@ -2955,13 +3050,18 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
!find_field_in_table(thd, natural_join_table, field_name, !find_field_in_table(thd, natural_join_table, field_name,
field_name, field_name,
strlen(field_name), &not_used_item, 0, 0, 0, strlen(field_name), &not_used_item, 0, 0, 0,
&not_used_field_index)) &not_used_field_index, TRUE))
{ {
Item *item= iterator->item(thd); Item *item= iterator->item(thd);
if (!found++) if (!found++)
(void) it->replace(item); // Replace '*' (void) it->replace(item); // Replace '*'
else else
it->after(item); it->after(item);
if (view && !thd->lex->current_select->no_wrap_view_item)
{
item= new Item_ref(it->ref(), tables->view_name.str,
field_name);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (any_privileges) if (any_privileges)
{ {
@ -3026,8 +3126,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
thd->mem_root); thd->mem_root);
} }
} }
/* All fields are used */ /*
table->used_fields=table->fields; All fields are used in case if usual tables (in case of view used
fields merked in setu_tables during fix_fields of view columns
*/
if (table)
table->used_fields=table->fields;
} }
} }
if (found) if (found)
@ -3045,10 +3149,16 @@ err:
/* /*
** Fix all conditions and outer join expressions Fix all conditions and outer join expressions
SYNOPSIS
setup_conds()
thd thread handler
tables list of tables for name resolving
leaves list of leaves of join table tree
*/ */
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
{ {
table_map not_null_tables= 0; table_map not_null_tables= 0;
SELECT_LEX *select_lex= thd->lex->current_select; SELECT_LEX *select_lex= thd->lex->current_select;
@ -3074,7 +3184,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
} }
/* Check if we are using outer joins */ /* Check if we are using outer joins */
for (table= tables; table; table= table->next_local) for (table= leaves; table; table= table->next_leaf)
{ {
TABLE_LIST *embedded; TABLE_LIST *embedded;
TABLE_LIST *embedding= table; TABLE_LIST *embedding= table;
@ -3138,8 +3248,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
Field_iterator_view view_iter; Field_iterator_view view_iter;
Field_iterator *iterator; Field_iterator *iterator;
Field *t1_field, *t2_field; Field *t1_field, *t2_field;
Item *item_t2; Item *item_t2= 0;
Item_cond_and *cond_and=new Item_cond_and(); Item_cond_and *cond_and= new Item_cond_and();
if (!cond_and) // If not out of memory if (!cond_and) // If not out of memory
goto err_no_arena; goto err_no_arena;
@ -3165,7 +3275,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
t1_field_name, t1_field_name,
strlen(t1_field_name), &item_t2, strlen(t1_field_name), &item_t2,
0, 0, 0, 0, 0, 0,
&not_used_field_index))) &not_used_field_index,
FALSE)))
{ {
if (t2_field != view_ref_found) if (t2_field != view_ref_found)
{ {

View File

@ -1650,7 +1650,9 @@ public:
class multi_update :public select_result_interceptor class multi_update :public select_result_interceptor
{ {
TABLE_LIST *all_tables, *update_tables, *table_being_updated; TABLE_LIST *all_tables; /* query/update command tables */
TABLE_LIST *leaves; /* list of leves of join table tree */
TABLE_LIST *update_tables, *table_being_updated;
THD *thd; THD *thd;
TABLE **tmp_tables, *main_table, *table_to_update; TABLE **tmp_tables, *main_table, *table_to_update;
TMP_TABLE_PARAM *tmp_table_param; TMP_TABLE_PARAM *tmp_table_param;
@ -1663,8 +1665,9 @@ class multi_update :public select_result_interceptor
bool do_update, trans_safe, transactional_tables, log_delayed; bool do_update, trans_safe, transactional_tables, log_delayed;
public: public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields, multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,
List<Item> *values, enum_duplicates handle_duplicates); List<Item> *fields, List<Item> *values,
enum_duplicates handle_duplicates);
~multi_update(); ~multi_update();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items); bool send_data(List<Item> &items);

View File

@ -44,7 +44,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (open_and_lock_tables(thd, table_list)) if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
table= table_list->table; if (!(table= table_list->table))
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
}
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init"; thd->proc_info="init";
table->map=1; table->map=1;
@ -289,8 +296,8 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete"); DBUG_ENTER("mysql_prepare_delete");
if (setup_tables(thd, table_list, conds) || if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
setup_conds(thd, table_list, conds) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
setup_ftfuncs(select_lex)) setup_ftfuncs(select_lex))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (!table_list->updatable || check_key_in_view(thd, table_list)) if (!table_list->updatable || check_key_in_view(thd, table_list))
@ -345,7 +352,8 @@ bool mysql_multi_delete_prepare(THD *thd)
lex->query_tables also point on local list of DELETE SELECT_LEX lex->query_tables also point on local list of DELETE SELECT_LEX
*/ */
if (setup_tables(thd, lex->query_tables, &lex->select_lex.where)) if (setup_tables(thd, lex->query_tables, &lex->select_lex.where,
&lex->select_lex.leaf_tables, 0))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/* Fix tables-to-be-deleted-from list to point at opened tables */ /* Fix tables-to-be-deleted-from list to point at opened tables */

View File

@ -618,6 +618,7 @@ bool mysqld_help(THD *thd, const char *mask)
st_find_field used_fields[array_elements(init_used_fields)]; st_find_field used_fields[array_elements(init_used_fields)];
DBUG_ENTER("mysqld_help"); DBUG_ENTER("mysqld_help");
TABLE_LIST *leaves= 0;
TABLE_LIST tables[4]; TABLE_LIST tables[4];
bzero((gptr)tables,sizeof(tables)); bzero((gptr)tables,sizeof(tables));
tables[0].alias= tables[0].real_name= (char*) "help_topic"; tables[0].alias= tables[0].real_name= (char*) "help_topic";
@ -646,7 +647,7 @@ bool mysqld_help(THD *thd, const char *mask)
tables do not contain VIEWs => we can pass 0 as conds tables do not contain VIEWs => we can pass 0 as conds
*/ */
setup_tables(thd, tables, 0); setup_tables(thd, tables, 0, &leaves, 0);
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields)); memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
if (init_fields(thd, tables, used_fields, array_elements(used_fields))) if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
goto error; goto error;

View File

@ -21,6 +21,7 @@
#include "sql_acl.h" #include "sql_acl.h"
#include "sp_head.h" #include "sp_head.h"
#include "sql_trigger.h" #include "sql_trigger.h"
#include "sql_select.h"
static int check_null_fields(THD *thd,TABLE *entry); static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
@ -31,6 +32,7 @@ static void end_delayed_insert(THD *thd);
extern "C" pthread_handler_decl(handle_delayed_insert,arg); extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table); static void unlink_blobs(register TABLE *table);
#endif #endif
static bool check_view_insertability(TABLE_LIST *view, ulong query_id);
/* Define to force use of my_malloc() if the allocated memory block is big */ /* Define to force use of my_malloc() if the allocated memory block is big */
@ -54,8 +56,22 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
{ {
TABLE *table= table_list->table; TABLE *table= table_list->table;
if (!table_list->updatable)
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}
if (fields.elements == 0 && values.elements != 0) if (fields.elements == 0 && values.elements != 0)
{ {
if (!table)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
table_list->view_db.str, table_list->view_name.str);
return -1;
}
if (values.elements != table->fields) if (values.elements != table->fields)
{ {
my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
@ -93,6 +109,23 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
thd->lex->select_lex.no_wrap_view_item= 0; thd->lex->select_lex.no_wrap_view_item= 0;
if (res) if (res)
return -1; return -1;
if (table == 0)
{
/* it is join view => we need to find table for update */
List_iterator_fast<Item> it(fields);
Item *item;
TABLE_LIST *tbl= 0;
table_map map= 0;
while (item= it++)
map|= item->used_tables();
if (table_list->check_single_table(&tbl, map) || tbl == 0)
{
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
table_list->view_db.str, table_list->view_name.str);
return -1;
}
table_list->table= table= tbl->table;
}
if (check_unique && thd->dupp_field) if (check_unique && thd->dupp_field)
{ {
@ -107,6 +140,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
#endif #endif
if (check_key_in_view(thd, table_list) ||
(table_list->view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1;
}
return 0; return 0;
} }
@ -131,7 +173,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
ulong counter = 1; ulong counter = 1;
ulonglong id; ulonglong id;
COPY_INFO info; COPY_INFO info;
TABLE *table; TABLE *table= 0;
List_iterator_fast<List_item> its(values_list); List_iterator_fast<List_item> its(values_list);
List_item *values; List_item *values;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
@ -197,17 +239,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (res || thd->is_fatal_error) if (res || thd->is_fatal_error)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
table= table_list->table;
thd->proc_info="init"; thd->proc_info="init";
thd->used_tables=0; thd->used_tables=0;
values= its++; values= its++;
if (duplic == DUP_UPDATE && !table->insert_values) if (duplic == DUP_UPDATE)
{ {
/* it should be allocated before Item::fix_fields() */ /* it should be allocated before Item::fix_fields() */
table->insert_values= if (table_list->set_insert_values(thd->mem_root))
(byte *)alloc_root(thd->mem_root, table->rec_buff_length);
if (!table->insert_values)
goto abort; goto abort;
} }
@ -215,6 +254,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
update_fields, update_values, duplic)) update_fields, update_values, duplic))
goto abort; goto abort;
/* mysql_prepare_insert set table_list->table if it was not set */
table= table_list->table;
// is table which we are changing used somewhere in other parts of query // is table which we are changing used somewhere in other parts of query
value_count= values->elements; value_count= values->elements;
while ((values= its++)) while ((values= its++))
@ -464,7 +506,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
::send_ok(thd, (ulong) thd->row_count_func, id, buff); ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
} }
free_underlaid_joins(thd, &thd->lex->select_lex); free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0; table_list->clear_insert_values();
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
@ -474,7 +516,7 @@ abort:
end_delayed_insert(thd); end_delayed_insert(thd);
#endif #endif
free_underlaid_joins(thd, &thd->lex->select_lex); free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0; table_list->clear_insert_values();
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
@ -505,8 +547,9 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
{ {
uint num= view->view->select_lex.item_list.elements; uint num= view->view->select_lex.item_list.elements;
TABLE *table= view->table; TABLE *table= view->table;
Item **trans_start= view->field_translation, **trans_end=trans_start+num; Field_translator *trans_start= view->field_translation,
Item **trans; *trans_end= trans_start + num;
Field_translator *trans;
Field **field_ptr= table->field; Field **field_ptr= table->field;
ulong other_query_id= query_id - 1; ulong other_query_id= query_id - 1;
DBUG_ENTER("check_key_in_view"); DBUG_ENTER("check_key_in_view");
@ -519,19 +562,23 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
{ {
Item_field *field; Item_field *field;
/* simple SELECT list entry (field without expression) */ /* simple SELECT list entry (field without expression) */
if (!(field= (*trans)->filed_for_view_update())) if (!(field= trans->item->filed_for_view_update()))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (field->field->unireg_check == Field::NEXT_NUMBER) if (field->field->unireg_check == Field::NEXT_NUMBER)
view->contain_auto_increment= 1; view->contain_auto_increment= 1;
/* prepare unique test */ /* prepare unique test */
field->field->query_id= other_query_id; field->field->query_id= other_query_id;
*trans= field; // remove collation if we have it /*
remove collation (or other transparent for update function) if we have
it
*/
trans->item= field;
} }
/* unique test */ /* unique test */
for (trans= trans_start; trans != trans_end; trans++) for (trans= trans_start; trans != trans_end; trans++)
{ {
/* Thanks to test above, we know that all columns are of type Item_field */ /* Thanks to test above, we know that all columns are of type Item_field */
Item_field *field= (Item_field *)(*trans); Item_field *field= (Item_field *)trans->item;
if (field->field->query_id == query_id) if (field->field->query_id == query_id)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
field->field->query_id= query_id; field->field->query_id= query_id;
@ -550,7 +597,7 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
{ {
if (trans == trans_end) if (trans == trans_end)
DBUG_RETURN(TRUE); // Field was not part of view DBUG_RETURN(TRUE); // Field was not part of view
if (((Item_field *)(*trans))->field == *field_ptr) if (((Item_field *)trans->item)->field == *field_ptr)
break; // ok break; // ok
} }
} }
@ -570,33 +617,35 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
where Pointer to where clause where Pointer to where clause
RETURN RETURN
0 ok 0 ok
1 ERROR 1 ERROR and message sent to client
-1 ERROR but message is not sent to client
*/ */
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, COND **where) List<Item> &fields, COND **where)
{ {
bool insert_into_view= (table_list->view != 0); bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert_check_table"); DBUG_ENTER("mysql_prepare_insert_check_table");
if (setup_tables(thd, table_list, where)) if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
DBUG_RETURN(1); 0))
DBUG_RETURN(thd->net.report_error ? -1 : 1);
if (insert_into_view && !fields.elements) if (insert_into_view && !fields.elements)
{ {
thd->lex->empty_field_list_on_rset= 1; thd->lex->empty_field_list_on_rset= 1;
insert_view_fields(&fields, table_list); if (!table_list->table)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
}
DBUG_RETURN(insert_view_fields(&fields, table_list));
} }
if (!table_list->updatable ||
check_key_in_view(thd, table_list) ||
(insert_into_view &&
check_view_insertability(table_list, thd->query_id)))
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
DBUG_RETURN(1);
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
@ -625,8 +674,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
bool res; bool res;
DBUG_ENTER("mysql_prepare_insert"); DBUG_ENTER("mysql_prepare_insert");
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds)) if ((res= mysql_prepare_insert_check_table(thd, table_list,
DBUG_RETURN(-1); fields, &unused_conds)))
DBUG_RETURN(res);
if (check_insert_fields(thd, table_list, fields, *values, 1, if (check_insert_fields(thd, table_list, fields, *values, 1,
!insert_into_view) || !insert_into_view) ||
@ -1654,6 +1704,10 @@ bool delayed_insert::handle_inserts(void)
bool mysql_insert_select_prepare(THD *thd) bool mysql_insert_select_prepare(THD *thd)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
TABLE_LIST* first_select_table=
(TABLE_LIST*)lex->select_lex.table_list.first;
TABLE_LIST* first_select_leaf_table;
int res;
DBUG_ENTER("mysql_insert_select_prepare"); DBUG_ENTER("mysql_insert_select_prepare");
/* /*
SELECT_LEX do not belong to INSERT statement, so we can't add WHERE SELECT_LEX do not belong to INSERT statement, so we can't add WHERE
@ -1663,7 +1717,28 @@ bool mysql_insert_select_prepare(THD *thd)
if (mysql_prepare_insert_check_table(thd, lex->query_tables, if (mysql_prepare_insert_check_table(thd, lex->query_tables,
lex->field_list, lex->field_list,
&lex->select_lex.where)) &lex->select_lex.where))
DBUG_RETURN(TRUE); DBUG_RETURN(FALSE);
/*
setup was done in mysql_insert_select_prepare, but we have to mark
first local table
*/
if (first_select_table)
first_select_table->setup_is_done= 1;
/*
exclude first table from leaf tables list, because it belong to
INSERT
*/
DBUG_ASSERT(lex->select_lex.leaf_tables);
lex->leaf_tables_insert= lex->select_lex.leaf_tables;
/* skip all leaf tables belonged to view where we are insert */
for (first_select_leaf_table= lex->select_lex.leaf_tables->next_leaf;
first_select_leaf_table &&
first_select_leaf_table->belong_to_view &&
first_select_leaf_table->belong_to_view ==
lex->leaf_tables_insert->belong_to_view;
first_select_leaf_table= first_select_leaf_table->next_leaf)
{}
lex->select_lex.leaf_tables= first_select_leaf_table;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
@ -1692,6 +1767,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (check_insert_fields(thd, table_list, *fields, values, 1, if (check_insert_fields(thd, table_list, *fields, values, 1,
!insert_into_view)) !insert_into_view))
DBUG_RETURN(1); DBUG_RETURN(1);
/*
if it is INSERT into join view then check_insert_fields already found
real table for insert
*/
table= table_list->table;
/*
Is table which we are changing used somewhere in other parts of
query
*/
if (!(thd->lex->current_select->options & OPTION_BUFFER_RESULT) &&
unique_table(table_list, table_list->next_global))
{
/* Using same table for INSERT and SELECT */
thd->lex->current_select->options|= OPTION_BUFFER_RESULT;
thd->lex->current_select->join->select_options|= OPTION_BUFFER_RESULT;
}
restore_record(table,default_values); // Get empty record restore_record(table,default_values); // Get empty record
table->next_number_field=table->found_next_number_field; table->next_number_field=table->found_next_number_field;

View File

@ -150,7 +150,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->found_colon= 0; lex->found_colon= 0;
lex->safe_to_cache_query= 1; lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0; lex->time_zone_tables_used= 0;
lex->proc_table= lex->query_tables= 0; lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables; lex->query_tables_last= &lex->query_tables;
lex->variables_used= 0; lex->variables_used= 0;
lex->select_lex.parent_lex= lex; lex->select_lex.parent_lex= lex;
@ -1049,7 +1049,7 @@ void st_select_lex::init_query()
table_list.empty(); table_list.empty();
top_join_list.empty(); top_join_list.empty();
join_list= &top_join_list; join_list= &top_join_list;
embedding= 0; embedding= leaf_tables= 0;
item_list.empty(); item_list.empty();
join= 0; join= 0;
where= prep_where= 0; where= prep_where= 0;
@ -1644,7 +1644,7 @@ bool st_lex::can_be_merged()
select_lex.group_list.elements == 0 && select_lex.group_list.elements == 0 &&
select_lex.having == 0 && select_lex.having == 0 &&
select_lex.with_sum_func == 0 && select_lex.with_sum_func == 0 &&
select_lex.table_list.elements == 1 && select_lex.table_list.elements >= 1 &&
!(select_lex.options & SELECT_DISTINCT) && !(select_lex.options & SELECT_DISTINCT) &&
select_lex.select_limit == HA_POS_ERROR); select_lex.select_limit == HA_POS_ERROR);
} }

View File

@ -447,6 +447,7 @@ public:
List<TABLE_LIST> top_join_list; /* join list of the top level */ List<TABLE_LIST> top_join_list; /* join list of the top level */
List<TABLE_LIST> *join_list; /* list for the currently parsed join */ List<TABLE_LIST> *join_list; /* list for the currently parsed join */
TABLE_LIST *embedding; /* table embedding to the above list */ TABLE_LIST *embedding; /* table embedding to the above list */
TABLE_LIST *leaf_tables; /* list of leaves in join table tree */
const char *type; /* type of select for EXPLAIN */ const char *type; /* type of select for EXPLAIN */
SQL_LIST order_list; /* ORDER clause */ SQL_LIST order_list; /* ORDER clause */
@ -669,6 +670,8 @@ typedef struct st_lex
*/ */
TABLE_LIST **query_tables_last; TABLE_LIST **query_tables_last;
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */ TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
List<key_part_spec> col_list; List<key_part_spec> col_list;
List<key_part_spec> ref_list; List<key_part_spec> ref_list;
@ -707,6 +710,7 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns; uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option; uint fk_delete_opt, fk_update_opt, fk_match_option;
uint slave_thd_opt, start_transaction_opt; uint slave_thd_opt, start_transaction_opt;
uint table_count; /* used when usual update transformed in multiupdate */
uint8 describe; uint8 describe;
uint8 derived_tables; uint8 derived_tables;
uint8 create_view_algorithm; uint8 create_view_algorithm;

View File

@ -121,9 +121,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table_list->lock_type= lock_type; table_list->lock_type= lock_type;
if (open_and_lock_tables(thd, table_list)) if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (setup_tables(thd, table_list, &unused_conds)) if (setup_tables(thd, table_list, &unused_conds,
&thd->lex->select_lex.leaf_tables, 0))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (!table_list->updatable || check_key_in_view(thd, table_list)) if (!table_list->table || // do not suport join view
!table_list->updatable || // and derived tables
check_key_in_view(thd, table_list))
{ {
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD"); my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "LOAD");
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -143,7 +146,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
thd->dupp_field=0; thd->dupp_field=0;
/* TODO: use this conds for 'WITH CHECK OPTIONS' */ /* TODO: use this conds for 'WITH CHECK OPTIONS' */
Item *unused_conds= 0; Item *unused_conds= 0;
if (setup_tables(thd, table_list, &unused_conds) || TABLE_LIST *leaves= 0;
if (setup_tables(thd, table_list, &unused_conds, &leaves, 0) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0)) setup_fields(thd, 0, table_list, fields, 1, 0, 0))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (thd->dupp_field) if (thd->dupp_field)

View File

@ -153,7 +153,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first if (setup_tables(lex->thd, (TABLE_LIST *)select_lex->table_list.first
&select_lex->where) || &select_lex->where, &select_lex->leaf_tables, 0) ||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
select_lex->item_list, 1, &all_fields,1) || select_lex->item_list, 1, &all_fields,1) ||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first, setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,

View File

@ -2882,12 +2882,19 @@ create_error:
(ORDER *) select_lex->order_list.first, (ORDER *) select_lex->order_list.first,
select_lex->select_limit, select_lex->select_limit,
lex->duplicates); lex->duplicates);
break; if (res != 2)
break;
case SQLCOM_UPDATE_MULTI: case SQLCOM_UPDATE_MULTI:
{ {
DBUG_ASSERT(first_table == all_tables && first_table != 0); DBUG_ASSERT(first_table == all_tables && first_table != 0);
if ((res= multi_update_precheck(thd, all_tables))) if (res != 2)
break; {
if ((res= multi_update_precheck(thd, all_tables)))
break;
}
else
res= 0;
res= mysql_multi_update(thd, all_tables, res= mysql_multi_update(thd, all_tables,
&select_lex->item_list, &select_lex->item_list,
&lex->value_list, &lex->value_list,
@ -2929,35 +2936,28 @@ create_error:
if (!(res= open_and_lock_tables(thd, all_tables))) if (!(res= open_and_lock_tables(thd, all_tables)))
{ {
/* /* Skip first table, which is the table we are inserting in */
Is table which we are changing used somewhere in other parts of lex->select_lex.table_list.first= (byte*)first_table->next_local;
query
*/
if (unique_table(first_table, all_tables->next_global))
{
/* Using same table for INSERT and SELECT */
select_lex->options |= OPTION_BUFFER_RESULT;
}
if ((res= mysql_insert_select_prepare(thd))) res= mysql_insert_select_prepare(thd);
break; if (!res && (result= new select_insert(first_table, first_table->table,
if ((result= new select_insert(first_table, first_table->table, &lex->field_list,
&lex->field_list, lex->duplicates, lex->duplicates,
lex->duplicates == DUP_IGNORE))) lex->duplicates == DUP_IGNORE)))
{ {
/* Skip first table, which is the table we are inserting in */ TABLE_LIST *first_select_table;
lex->select_lex.table_list.first= (byte*) first_table->next_local;
/* /*
insert/replace from SELECT give its SELECT_LEX for SELECT, insert/replace from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT and item_list belong to SELECT
*/ */
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
res= handle_select(thd, lex, result); res= handle_select(thd, lex, result);
/* revert changes for SP */
lex->select_lex.table_list.first= (byte*) first_table;
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE; lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result; delete result;
} }
/* revert changes for SP */
lex->select_lex.table_list.first= (byte*) first_table;
} }
else else
res= TRUE; res= TRUE;
@ -3012,8 +3012,20 @@ create_error:
goto error; goto error;
thd->proc_info="init"; thd->proc_info="init";
if ((res= open_and_lock_tables(thd, all_tables)) || if ((res= open_and_lock_tables(thd, all_tables)))
(res= mysql_multi_delete_prepare(thd))) break;
if (!first_table->table)
{
DBUG_ASSERT(first_table->view &&
first_table->ancestor && first_table->ancestor->next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
first_table->view_db.str, first_table->view_name.str);
res= -1;
break;
}
if ((res= mysql_multi_delete_prepare(thd)))
goto error; goto error;
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables, if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,

View File

@ -935,22 +935,32 @@ error:
tables list of tables queries tables list of tables queries
RETURN VALUE RETURN VALUE
FALSE success 0 success
TRUE error 2 convert to multi_update
1 error
*/ */
static bool mysql_test_update(Prepared_statement *stmt, static int mysql_test_update(Prepared_statement *stmt,
TABLE_LIST *table_list) TABLE_LIST *table_list)
{ {
bool res; int res;
THD *thd= stmt->thd; THD *thd= stmt->thd;
SELECT_LEX *select= &stmt->lex->select_lex; SELECT_LEX *select= &stmt->lex->select_lex;
DBUG_ENTER("mysql_test_update"); DBUG_ENTER("mysql_test_update");
if ((res= update_precheck(thd, table_list))) if (update_precheck(thd, table_list))
DBUG_RETURN(res); DBUG_RETURN(1);
if (!(res=open_and_lock_tables(thd, table_list))) if (!(res=open_and_lock_tables(thd, table_list)))
{ {
if (table_list->table == 0)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
stmt->lex->sql_command= SQLCOM_UPDATE_MULTI;
DBUG_PRINT("info", ("Switch to multi-update (command replaced)"));
/* convert to multiupdate */
return 2;
}
if (!(res= mysql_prepare_update(thd, table_list, if (!(res= mysql_prepare_update(thd, table_list,
&select->where, &select->where,
select->order_list.elements, select->order_list.elements,
@ -959,7 +969,7 @@ static bool mysql_test_update(Prepared_statement *stmt,
thd->lex->select_lex.no_wrap_view_item= 1; thd->lex->select_lex.no_wrap_view_item= 1;
if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0)) if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0))
{ {
res= -1; res= 1;
thd->lex->select_lex.no_wrap_view_item= 0; thd->lex->select_lex.no_wrap_view_item= 0;
} }
else else
@ -967,7 +977,7 @@ static bool mysql_test_update(Prepared_statement *stmt,
thd->lex->select_lex.no_wrap_view_item= 0; thd->lex->select_lex.no_wrap_view_item= 0;
if (setup_fields(thd, 0, table_list, if (setup_fields(thd, 0, table_list,
stmt->lex->value_list, 0, 0, 0)) stmt->lex->value_list, 0, 0, 0))
res= -1; res= 1;
} }
} }
stmt->lex->unit.cleanup(); stmt->lex->unit.cleanup();
@ -1001,6 +1011,15 @@ static int mysql_test_delete(Prepared_statement *stmt,
if (!open_and_lock_tables(thd, table_list)) if (!open_and_lock_tables(thd, table_list))
{ {
if (!table_list->table)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
table_list->view_db.str, table_list->view_name.str);
DBUG_RETURN(-1);
}
mysql_prepare_delete(thd, table_list, &lex->select_lex.where); mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
lex->unit.cleanup(); lex->unit.cleanup();
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
@ -1195,7 +1214,10 @@ static bool select_like_statement_test(Prepared_statement *stmt,
LEX *lex= stmt->lex; LEX *lex= stmt->lex;
bool res= 0; bool res= 0;
if (tables && (res= open_and_lock_tables(thd, tables))) /* check that tables was not opened during conversion from usual update */
if (tables &&
(!tables->table && !tables->view) &&
(res= open_and_lock_tables(thd, tables)))
goto end; goto end;
if (specific_prepare && (res= (*specific_prepare)(thd))) if (specific_prepare && (res= (*specific_prepare)(thd)))
@ -1261,6 +1283,7 @@ static int mysql_test_create_table(Prepared_statement *stmt)
mysql_test_multiupdate() mysql_test_multiupdate()
stmt prepared statemen handler stmt prepared statemen handler
tables list of tables queries tables list of tables queries
converted converted to multi-update from usual update
RETURN VALUE RETURN VALUE
FALSE success FALSE success
@ -1268,9 +1291,10 @@ static int mysql_test_create_table(Prepared_statement *stmt)
*/ */
static bool mysql_test_multiupdate(Prepared_statement *stmt, static bool mysql_test_multiupdate(Prepared_statement *stmt,
TABLE_LIST *tables) TABLE_LIST *tables,
bool converted)
{ {
if (multi_update_precheck(stmt->thd, tables)) if (!converted && multi_update_precheck(stmt->thd, tables))
return TRUE; return TRUE;
/* /*
here we do not pass tables for opening, tables will be opened and locked here we do not pass tables for opening, tables will be opened and locked
@ -1304,7 +1328,19 @@ static int mysql_test_multidelete(Prepared_statement *stmt,
uint fake_counter; uint fake_counter;
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter))) if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
return res; return res;
return select_like_statement_test(stmt, tables, &mysql_multi_delete_prepare); if ((res= select_like_statement_test(stmt, tables,
&mysql_multi_delete_prepare)))
return res;
if (!tables->table)
{
DBUG_ASSERT(tables->view &&
tables->ancestor && tables->ancestor->next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
tables->view_db.str, tables->view_name.str);
return -1;
}
return 0;
} }
@ -1406,6 +1442,11 @@ static int check_prepared_statement(Prepared_statement *stmt,
case SQLCOM_UPDATE: case SQLCOM_UPDATE:
res= mysql_test_update(stmt, tables); res= mysql_test_update(stmt, tables);
if (res != 2)
break;
case SQLCOM_UPDATE_MULTI:
res= mysql_test_multiupdate(stmt, tables, res == 2);
break; break;
case SQLCOM_DELETE: case SQLCOM_DELETE:
@ -1434,10 +1475,6 @@ static int check_prepared_statement(Prepared_statement *stmt,
res= mysql_test_multidelete(stmt, tables); res= mysql_test_multidelete(stmt, tables);
break; break;
case SQLCOM_UPDATE_MULTI:
res= mysql_test_multiupdate(stmt, tables);
break;
case SQLCOM_INSERT_SELECT: case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT: case SQLCOM_REPLACE_SELECT:
res= mysql_test_insert_select(stmt, tables); res= mysql_test_insert_select(stmt, tables);
@ -1720,8 +1757,15 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
were closed in the end of previous prepare or execute call. were closed in the end of previous prepare or execute call.
*/ */
tables->table= 0; tables->table= 0;
if (tables->nested_join)
tables->nested_join->counter= 0;
} }
lex->current_select= &lex->select_lex; lex->current_select= &lex->select_lex;
/* restore original list used in INSERT ... SELECT */
if (lex->leaf_tables_insert)
lex->select_lex.leaf_tables= lex->leaf_tables_insert;
if (lex->result) if (lex->result)
lex->result->cleanup(); lex->result->cleanup();

View File

@ -38,7 +38,7 @@ const key_map key_map_empty(0);
const key_map key_map_full(~0); const key_map key_map_full(~0);
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
DYNAMIC_ARRAY *keyuse); DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab, JOIN_TAB *join_tab,
@ -250,6 +250,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result)
*/ */
inline int setup_without_group(THD *thd, Item **ref_pointer_array, inline int setup_without_group(THD *thd, Item **ref_pointer_array,
TABLE_LIST *tables, TABLE_LIST *tables,
TABLE_LIST *leaves,
List<Item> &fields, List<Item> &fields,
List<Item> &all_fields, List<Item> &all_fields,
COND **conds, COND **conds,
@ -262,7 +263,7 @@ inline int setup_without_group(THD *thd, Item **ref_pointer_array,
save_allow_sum_func= thd->allow_sum_func; save_allow_sum_func= thd->allow_sum_func;
thd->allow_sum_func= 0; thd->allow_sum_func= 0;
res= (setup_conds(thd, tables, conds) || res= (setup_conds(thd, tables, leaves, conds) ||
setup_order(thd, ref_pointer_array, tables, fields, all_fields, setup_order(thd, ref_pointer_array, tables, fields, all_fields,
order) || order) ||
setup_group(thd, ref_pointer_array, tables, fields, all_fields, setup_group(thd, ref_pointer_array, tables, fields, all_fields,
@ -309,12 +310,13 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */ /* Check that all tables, fields, conds and order are ok */
if (setup_tables(thd, tables_list, &conds) || if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 0) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) || select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
&all_fields, 1) || &all_fields, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list, setup_without_group(thd, (*rref_pointer_array), tables_list,
select_lex->leaf_tables, fields_list,
all_fields, &conds, order, group_list, all_fields, &conds, order, group_list,
&hidden_group_fields)) &hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
@ -383,7 +385,9 @@ JOIN::prepare(Item ***rref_pointer_array,
} }
} }
TABLE_LIST *table_ptr; TABLE_LIST *table_ptr;
for (table_ptr= tables_list; table_ptr; table_ptr= table_ptr->next_local) for (table_ptr= select_lex->leaf_tables;
table_ptr;
table_ptr= table_ptr->next_leaf)
tables++; tables++;
} }
{ {
@ -585,7 +589,7 @@ JOIN::optimize()
opt_sum_query() returns -1 if no rows match to the WHERE conditions, opt_sum_query() returns -1 if no rows match to the WHERE conditions,
or 1 if all items were resolved, or 0, or an error number HA_ERR_... or 1 if all items were resolved, or 0, or an error number HA_ERR_...
*/ */
if ((res=opt_sum_query(tables_list, all_fields, conds))) if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
{ {
if (res > 1) if (res > 1)
{ {
@ -611,11 +615,11 @@ JOIN::optimize()
DBUG_RETURN(0); DBUG_RETURN(0);
} }
error= -1; // Error is sent to client error= -1; // Error is sent to client
sort_by_table= get_sort_by_table(order, group_list, tables_list); sort_by_table= get_sort_by_table(order, group_list, select_lex->leaf_tables);
/* Calculate how to do the join */ /* Calculate how to do the join */
thd->proc_info= "statistics"; thd->proc_info= "statistics";
if (make_join_statistics(this, tables_list, conds, &keyuse) || if (make_join_statistics(this, select_lex->leaf_tables, conds, &keyuse) ||
thd->is_fatal_error) thd->is_fatal_error)
{ {
DBUG_PRINT("error",("Error: make_join_statistics() failed")); DBUG_PRINT("error",("Error: make_join_statistics() failed"));
@ -1077,7 +1081,7 @@ JOIN::reinit()
if (tables_list) if (tables_list)
{ {
tables_list->setup_is_done= 0; tables_list->setup_is_done= 0;
if (setup_tables(thd, tables_list, &conds)) if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 1))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -1182,7 +1186,7 @@ JOIN::exec()
if (zero_result_cause) if (zero_result_cause)
{ {
(void) return_zero_rows(this, result, tables_list, fields_list, (void) return_zero_rows(this, result, select_lex->leaf_tables, fields_list,
send_row_on_empty_set(), send_row_on_empty_set(),
select_options, select_options,
zero_result_cause, zero_result_cause,
@ -2089,7 +2093,7 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
*/ */
static bool static bool
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
DYNAMIC_ARRAY *keyuse_array) DYNAMIC_ARRAY *keyuse_array)
{ {
int error; int error;
@ -2119,7 +2123,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
for (s= stat, i= 0; for (s= stat, i= 0;
tables; tables;
s++, tables= tables->next_local, i++) s++, tables= tables->next_leaf, i++)
{ {
TABLE_LIST *embedding= tables->embedding; TABLE_LIST *embedding= tables->embedding;
stat_vector[i]=s; stat_vector[i]=s;
@ -5078,6 +5082,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
static void static void
make_outerjoin_info(JOIN *join) make_outerjoin_info(JOIN *join)
{ {
DBUG_ENTER("make_outerjoin_info");
for (uint i=join->const_tables ; i < join->tables ; i++) for (uint i=join->const_tables ; i < join->tables ; i++)
{ {
JOIN_TAB *tab=join->join_tab+i; JOIN_TAB *tab=join->join_tab+i;
@ -5121,6 +5126,7 @@ make_outerjoin_info(JOIN *join)
nested_join->first_nested->last_inner= tab; nested_join->first_nested->last_inner= tab;
} }
} }
DBUG_VOID_RETURN;
} }
@ -5223,7 +5229,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
in the ON part of an OUTER JOIN. In this case we want the code in the ON part of an OUTER JOIN. In this case we want the code
below to check if we should use 'quick' instead. below to check if we should use 'quick' instead.
*/ */
DBUG_PRINT("info", ("Item_int"));
tmp= new Item_int((longlong) 1,1); // Always true tmp= new Item_int((longlong) 1,1); // Always true
DBUG_PRINT("info", ("Item_int 0x%lx", (ulong)tmp));
} }
} }
@ -5412,13 +5420,18 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
Now add the guard turning the predicate off for Now add the guard turning the predicate off for
the null complemented row. the null complemented row.
*/ */
DBUG_PRINT("info", ("Item_func_trig_cond"));
tmp= new Item_func_trig_cond(tmp, tmp= new Item_func_trig_cond(tmp,
&first_inner_tab->not_null_compl); &first_inner_tab->not_null_compl);
DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
if (tmp) if (tmp)
tmp->quick_fix_field(); tmp->quick_fix_field();
/* Add the predicate to other pushed down predicates */ /* Add the predicate to other pushed down predicates */
DBUG_PRINT("info", ("Item_cond_and"));
cond_tab->select_cond= !cond_tab->select_cond ? tmp : cond_tab->select_cond= !cond_tab->select_cond ? tmp :
new Item_cond_and(cond_tab->select_cond,tmp); new Item_cond_and(cond_tab->select_cond,tmp);
DBUG_PRINT("info", ("Item_cond_and 0x%lx",
(ulong)cond_tab->select_cond));
if (!cond_tab->select_cond) if (!cond_tab->select_cond)
DBUG_RETURN(1); DBUG_RETURN(1);
cond_tab->select_cond->quick_fix_field(); cond_tab->select_cond->quick_fix_field();
@ -5971,7 +5984,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (send_row) if (send_row)
{ {
for (TABLE_LIST *table= tables; table; table= table->next_local) for (TABLE_LIST *table= tables; table; table= table->next_leaf)
mark_as_null_row(table->table); // All fields are NULL mark_as_null_row(table->table); // All fields are NULL
if (having && having->val_int() == 0) if (having && having->val_int() == 0)
send_row=0; send_row=0;
@ -8815,6 +8828,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
join->thd->send_kill_message(); join->thd->send_kill_message();
return -2; /* purecov: inspected */ return -2; /* purecov: inspected */
} }
DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond));
if (!select_cond || select_cond->val_int()) if (!select_cond || select_cond->val_int())
{ {
/* /*
@ -11580,7 +11594,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT))) if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0); DBUG_RETURN(0);
for (; !(map & tables->table->map); tables= tables->next_local); for (; !(map & tables->table->map); tables= tables->next_leaf);
if (map != tables->table->map) if (map != tables->table->map)
DBUG_RETURN(0); // More than one table DBUG_RETURN(0); // More than one table
DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr)); DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));

View File

@ -86,25 +86,47 @@ static bool check_fields(THD *thd, List<Item> &items)
} }
bool mysql_update(THD *thd, /*
TABLE_LIST *table_list, Process usual UPDATE
List<Item> &fields,
List<Item> &values, SYNOPSIS
COND *conds, mysql_update()
uint order_num, ORDER *order, thd thread handler
ha_rows limit, fields fields for update
enum enum_duplicates handle_duplicates) values values of fields for update
conds WHERE clause expression
order_num number of elemen in ORDER BY clause
order ORDER BY clause list
limit limit clause
handle_duplicates how to handle duplicates
RETURN
0 - OK
2 - privilege check and openning table passed, but we need to convert to
multi-update because of view substitution
1 - error
*/
int mysql_update(THD *thd,
TABLE_LIST *table_list,
List<Item> &fields,
List<Item> &values,
COND *conds,
uint order_num, ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates)
{ {
bool using_limit= limit != HA_POS_ERROR; bool using_limit= limit != HA_POS_ERROR;
bool safe_update= thd->options & OPTION_SAFE_UPDATES; bool safe_update= thd->options & OPTION_SAFE_UPDATES;
bool used_key_is_modified, transactional_table, log_delayed; bool used_key_is_modified, transactional_table, log_delayed;
bool ignore_err= (thd->lex->duplicates == DUP_IGNORE); bool ignore_err= (thd->lex->duplicates == DUP_IGNORE);
bool res; int res;
int error=0; int error=0;
uint used_index; uint used_index;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege; uint want_privilege;
#endif #endif
uint table_count= 0;
ulong query_id=thd->query_id, timestamp_query_id; ulong query_id=thd->query_id, timestamp_query_id;
ha_rows updated, found; ha_rows updated, found;
key_map old_used_keys; key_map old_used_keys;
@ -117,8 +139,26 @@ bool mysql_update(THD *thd,
LINT_INIT(used_index); LINT_INIT(used_index);
LINT_INIT(timestamp_query_id); LINT_INIT(timestamp_query_id);
if (open_and_lock_tables(thd, table_list)) if (open_tables(thd, table_list, &table_count))
DBUG_RETURN(TRUE); DBUG_RETURN(1);
if (table_list->table == 0)
{
DBUG_ASSERT(table_list->view &&
table_list->ancestor && table_list->ancestor->next_local);
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
/* convert to multiupdate */
return 2;
}
if (lock_tables(thd, table_list, table_count) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(1);
thd->proc_info="init"; thd->proc_info="init";
table= table_list->table; table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@ -134,7 +174,7 @@ bool mysql_update(THD *thd,
table->grant.want_privilege); table->grant.want_privilege);
#endif #endif
if (mysql_prepare_update(thd, table_list, &conds, order_num, order)) if (mysql_prepare_update(thd, table_list, &conds, order_num, order))
DBUG_RETURN(TRUE); DBUG_RETURN(1);
old_used_keys= table->used_keys; // Keys used in WHERE old_used_keys= table->used_keys; // Keys used in WHERE
/* /*
@ -156,16 +196,16 @@ bool mysql_update(THD *thd,
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
select_lex->no_wrap_view_item= 0; select_lex->no_wrap_view_item= 0;
if (res) if (res)
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
} }
if (table_list->view && check_fields(thd, fields)) if (table_list->view && check_fields(thd, fields))
{ {
DBUG_RETURN(TRUE); DBUG_RETURN(1);
} }
if (!table_list->updatable || check_key_in_view(thd, table_list)) if (!table_list->updatable || check_key_in_view(thd, table_list))
{ {
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
DBUG_RETURN(TRUE); DBUG_RETURN(1);
} }
if (table->timestamp_field) if (table->timestamp_field)
{ {
@ -184,7 +224,7 @@ bool mysql_update(THD *thd,
if (setup_fields(thd, 0, table_list, values, 0, 0, 0)) if (setup_fields(thd, 0, table_list, values, 0, 0, 0))
{ {
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */
} }
// Don't count on usage of 'only index' when calculating which key to use // Don't count on usage of 'only index' when calculating which key to use
@ -197,10 +237,10 @@ bool mysql_update(THD *thd,
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
if (error) if (error)
{ {
DBUG_RETURN(TRUE); // Error in where DBUG_RETURN(1); // Error in where
} }
send_ok(thd); // No matching records send_ok(thd); // No matching records
DBUG_RETURN(FALSE); DBUG_RETURN(0);
} }
/* If running in safe sql mode, don't allow updates without keys */ /* If running in safe sql mode, don't allow updates without keys */
if (table->quick_keys.is_clear_all()) if (table->quick_keys.is_clear_all())
@ -472,7 +512,7 @@ bool mysql_update(THD *thd,
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
free_io_cache(table); free_io_cache(table);
DBUG_RETURN(error >= 0 || thd->net.report_error); DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
err: err:
delete select; delete select;
@ -483,7 +523,7 @@ err:
table->file->extra(HA_EXTRA_NO_KEYREAD); table->file->extra(HA_EXTRA_NO_KEYREAD);
} }
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(TRUE); DBUG_RETURN(1);
} }
/* /*
@ -519,8 +559,8 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
tables.table= table; tables.table= table;
tables.alias= table_list->alias; tables.alias= table_list->alias;
if (setup_tables(thd, table_list, conds) || if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
setup_conds(thd, table_list, conds) || setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
select_lex->setup_ref_array(thd, order_num) || select_lex->setup_ref_array(thd, order_num) ||
setup_order(thd, select_lex->ref_pointer_array, setup_order(thd, select_lex->ref_pointer_array,
table_list, all_fields, all_fields, order) || table_list, all_fields, all_fields, order) ||
@ -578,42 +618,53 @@ bool mysql_multi_update_prepare(THD *thd)
TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *table_list= lex->query_tables;
List<Item> *fields= &lex->select_lex.item_list; List<Item> *fields= &lex->select_lex.item_list;
TABLE_LIST *tl; TABLE_LIST *tl;
TABLE_LIST *leaves;
table_map tables_for_update; table_map tables_for_update;
int res; int res;
bool update_view= 0; bool update_view= 0;
uint table_count; /*
if this multi-update was converted from usual update, here is table
counter else junk will be assigned here, but then replaced with real
count in open_tables()
*/
uint table_count= lex->table_count;
const bool using_lock_tables= thd->locked_tables != 0; const bool using_lock_tables= thd->locked_tables != 0;
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
DBUG_ENTER("mysql_multi_update_prepare"); DBUG_ENTER("mysql_multi_update_prepare");
/* open tables and create derived ones, but do not lock and fill them */ /* open tables and create derived ones, but do not lock and fill them */
if (open_tables(thd, table_list, & table_count) || if ((original_multiupdate && open_tables(thd, table_list, & table_count)) ||
mysql_handle_derived(lex, &mysql_derived_prepare)) mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
/*
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
second time, but this call will do nothing (there are check for second
call in setup_tables()).
*/
if (setup_tables(thd, table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, 0))
DBUG_RETURN(TRUE);
/* /*
Ensure that we have update privilege for all tables and columns in the Ensure that we have update privilege for all tables and columns in the
SET part SET part
*/ */
for (tl= table_list; tl; tl= tl->next_local) for (tl= (leaves= lex->select_lex.leaf_tables); tl; tl= tl->next_leaf)
{ {
TABLE *table= tl->table;
/* /*
Update of derived tables is checked later Update of derived tables is checked later
We don't check privileges here, becasue then we would get error We don't check privileges here, becasue then we would get error
"UPDATE command denided .. for column N" instead of "UPDATE command denided .. for column N" instead of
"Target table ... is not updatable" "Target table ... is not updatable"
*/ */
if (!tl->derived) TABLE *table= tl->table;
tl->grant.want_privilege= table->grant.want_privilege= TABLE_LIST *tlist;
if (!(tlist= tl->belong_to_view?tl->belong_to_view:tl)->derived)
tlist->grant.want_privilege= table->grant.want_privilege=
(UPDATE_ACL & ~table->grant.privilege); (UPDATE_ACL & ~table->grant.privilege);
} }
/* if ((lex->select_lex.no_wrap_view_item= 1,
setup_tables() need for VIEWs. JOIN::prepare() will call setup_tables()
second time, but this call will do nothing (there are check for second
call in setup_tables()).
*/
if (setup_tables(thd, table_list, &lex->select_lex.where) ||
(lex->select_lex.no_wrap_view_item= 1,
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
lex->select_lex.no_wrap_view_item= 0, lex->select_lex.no_wrap_view_item= 0,
res)) res))
@ -638,14 +689,15 @@ bool mysql_multi_update_prepare(THD *thd)
/* /*
Setup timestamp handling and locking mode Setup timestamp handling and locking mode
*/ */
for (tl= table_list; tl ; tl= tl->next_local) for (tl= leaves; tl; tl= tl->next_leaf)
{ {
TABLE *table= tl->table; TABLE *table= tl->table;
TABLE_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl;
/* We only need SELECT privilege for columns in the values list */ /* We only need SELECT privilege for columns in the values list */
tl->grant.want_privilege= table->grant.want_privilege= tlist->grant.want_privilege= table->grant.want_privilege=
(SELECT_ACL & ~table->grant.privilege); (SELECT_ACL & ~table->grant.privilege);
// Only set timestamp column if this is not modified /* Only set timestamp column if this is not modified */
if (table->timestamp_field && if (table->timestamp_field &&
table->timestamp_field->query_id == thd->query_id) table->timestamp_field->query_id == thd->query_id)
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@ -683,6 +735,23 @@ bool mysql_multi_update_prepare(THD *thd)
tl->table->reginfo.lock_type= tl->lock_type; tl->table->reginfo.lock_type= tl->lock_type;
} }
/* check single table update for view compound from several tables */
for (tl= table_list; tl; tl= tl->next_local)
{
if (tl->table == 0)
{
DBUG_ASSERT(tl->view &&
tl->ancestor && tl->ancestor->next_local);
TABLE_LIST *for_update= 0;
if (tl->check_single_table(&for_update, tables_for_update))
{
my_error(ER_VIEW_MULTIUPDATE, MYF(0),
tl->view_db.str, tl->view_name.str);
DBUG_RETURN(-1);
}
}
}
opened_tables= thd->status_var.opened_tables; opened_tables= thd->status_var.opened_tables;
/* now lock and fill tables */ /* now lock and fill tables */
if (lock_tables(thd, table_list, table_count)) if (lock_tables(thd, table_list, table_count))
@ -712,7 +781,8 @@ bool mysql_multi_update_prepare(THD *thd)
/* undone setup_tables() */ /* undone setup_tables() */
table_list->setup_is_done= 0; table_list->setup_is_done= 0;
if (setup_tables(thd, table_list, &lex->select_lex.where) || if (setup_tables(thd, table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, 0) ||
(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), res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
lex->select_lex.no_wrap_view_item= 0, lex->select_lex.no_wrap_view_item= 0,
@ -739,14 +809,16 @@ bool mysql_multi_update(THD *thd,
enum enum_duplicates handle_duplicates, enum enum_duplicates handle_duplicates,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{ {
bool res; bool res= FALSE;
multi_update *result; multi_update *result;
DBUG_ENTER("mysql_multi_update"); DBUG_ENTER("mysql_multi_update");
if (mysql_multi_update_prepare(thd)) if (mysql_multi_update_prepare(thd))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
if (!(result= new multi_update(thd, table_list, fields, values, if (!(result= new multi_update(thd, table_list,
thd->lex->select_lex.leaf_tables,
fields, values,
handle_duplicates))) handle_duplicates)))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
@ -770,12 +842,14 @@ bool mysql_multi_update(THD *thd,
multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list, multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
TABLE_LIST *leaves_list,
List<Item> *field_list, List<Item> *value_list, List<Item> *field_list, List<Item> *value_list,
enum enum_duplicates handle_duplicates_arg) enum enum_duplicates handle_duplicates_arg)
:all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0), :all_tables(table_list), leaves(leaves_list), update_tables(0),
updated(0), found(0), fields(field_list), values(value_list), thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list),
table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), values(value_list), table_count(0), copy_field(0),
do_update(1), trans_safe(0), transactional_tables(1) handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
transactional_tables(1)
{} {}
@ -822,8 +896,9 @@ int multi_update::prepare(List<Item> &not_used_values,
*/ */
update.empty(); update.empty();
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{ {
/* TODO: add support of view of join support */
TABLE *table=table_ref->table; TABLE *table=table_ref->table;
if (tables_to_update & table->map) if (tables_to_update & table->map)
{ {
@ -890,7 +965,7 @@ int multi_update::prepare(List<Item> &not_used_values,
which will cause an error when reading a row. which will cause an error when reading a row.
(This issue is mostly relevent for MyISAM tables) (This issue is mostly relevent for MyISAM tables)
*/ */
for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local) for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{ {
TABLE *table=table_ref->table; TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) && if (!(tables_to_update & table->map) &&

View File

@ -485,17 +485,24 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
{ {
/* TODO: change here when we will support UNIONs */ /* TODO: change here when we will support UNIONs */
for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first; for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
tbl; tbl;
tbl= tbl->next_local) tbl= tbl->next_local)
{ {
if ((tbl->view && !tbl->updatable_view) || tbl->schema_table) if ((tbl->view && !tbl->updatable_view) || tbl->schema_table)
view->updatable_view= 0;
break;
}
for (TABLE_LIST *up= tbl; up; up= up->embedding)
{ {
view->updatable_view= 0; if (up->outer_join)
break; {
view->updatable_view= 0;
goto loop_out;
}
} }
} }
} }
loop_out:
/* /*
Check that table of main select do not used in subqueries. Check that table of main select do not used in subqueries.
@ -561,6 +568,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
SELECT_LEX *end; SELECT_LEX *end;
THD *thd= current_thd; THD *thd= current_thd;
LEX *old_lex= thd->lex, *lex; LEX *old_lex= thd->lex, *lex;
SELECT_LEX *view_select;
int res= 0; int res= 0;
/* /*
@ -603,7 +611,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
*/ */
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local; table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length); lex_start(thd, (uchar*)table->query.str, table->query.length);
lex->select_lex.select_number= ++thd->select_number; view_select= &lex->select_lex;
view_select->select_number= ++thd->select_number;
old_lex->derived_tables|= DERIVED_VIEW; old_lex->derived_tables|= DERIVED_VIEW;
{ {
ulong options= thd->options; ulong options= thd->options;
@ -646,6 +655,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table); table);
TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables= lex->query_tables;
TABLE_LIST *view_tables_tail= 0; TABLE_LIST *view_tables_tail= 0;
TABLE_LIST *tbl;
if (lex->spfuns.records) if (lex->spfuns.records)
{ {
@ -704,7 +714,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query && old_lex->safe_to_cache_query= (old_lex->safe_to_cache_query &&
lex->safe_to_cache_query); lex->safe_to_cache_query);
/* move SQL_CACHE to whole query */ /* move SQL_CACHE to whole query */
if (lex->select_lex.options & OPTION_TO_QUERY_CACHE) if (view_select->options & OPTION_TO_QUERY_CACHE)
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE; old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
/* /*
@ -741,9 +751,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
old_lex->can_use_merged()) && old_lex->can_use_merged()) &&
!old_lex->can_not_use_merged()) !old_lex->can_not_use_merged())
{ {
/*
TODO: support multi tables substitutions
*/
/* lex should contain at least one table */ /* lex should contain at least one table */
DBUG_ASSERT(view_tables != 0); DBUG_ASSERT(view_tables != 0);
@ -753,20 +760,48 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->effective_with_check= (uint8)table->with_check; table->effective_with_check= (uint8)table->with_check;
table->ancestor= view_tables; table->ancestor= view_tables;
/*
next table should include SELECT_LEX under this table SELECT_LEX
TODO: here should be loop for multi tables substitution /* next table should include SELECT_LEX under this table SELECT_LEX */
*/
table->ancestor->select_lex= table->select_lex; table->ancestor->select_lex= table->select_lex;
/* /*
move lock type (TODO: should we issue error in case of TMPTABLE Process upper level tables of view. As far as we do noy suport union
algorithm and non-read locking)? here we can go through local tables of view most upper SELECT
*/ */
view_tables->lock_type= table->lock_type; for(tbl= (TABLE_LIST*)view_select->table_list.first;
tbl;
tbl= tbl->next_local)
{
/*
move lock type (TODO: should we issue error in case of TMPTABLE
algorithm and non-read locking)?
*/
tbl->lock_type= table->lock_type;
}
/* multi table view */
if (view_tables->next_local)
{
/* make nested join structure for view tables */
NESTED_JOIN *nested_join;
if (!(nested_join= table->nested_join=
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
goto err;
nested_join->join_list= view_select->top_join_list;
/* re-nest tables of VIEW */
{
List_iterator_fast<TABLE_LIST> ti(nested_join->join_list);
while(tbl= ti++)
{
tbl->join_list= &nested_join->join_list;
tbl->embedding= table;
}
}
}
/* Store WHERE clause for post-processing in setup_ancestor */ /* Store WHERE clause for post-processing in setup_ancestor */
table->where= lex->select_lex.where; table->where= view_select->where;
/* /*
Add subqueries units to SELECT in which we merging current view. Add subqueries units to SELECT in which we merging current view.
@ -793,13 +828,13 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE; table->effective_algorithm= VIEW_ALGORITHM_TMPTABLE;
DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE")); DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
lex->select_lex.linkage= DERIVED_TABLE_TYPE; view_select->linkage= DERIVED_TABLE_TYPE;
table->updatable= 0; table->updatable= 0;
table->effective_with_check= VIEW_CHECK_NONE; table->effective_with_check= VIEW_CHECK_NONE;
/* SELECT tree link */ /* SELECT tree link */
lex->unit.include_down(table->select_lex); lex->unit.include_down(table->select_lex);
lex->unit.slave= &lex->select_lex; // fix include_down initialisation lex->unit.slave= view_select; // fix include_down initialisation
table->derived= &lex->unit; table->derived= &lex->unit;
} }
@ -810,7 +845,7 @@ ok:
if (arena) if (arena)
thd->restore_backup_item_arena(arena, &backup); thd->restore_backup_item_arena(arena, &backup);
/* global SELECT list linking */ /* global SELECT list linking */
end= &lex->select_lex; // primary SELECT_LEX is always last end= view_select; // primary SELECT_LEX is always last
end->link_next= old_lex->all_selects_list; end->link_next= old_lex->all_selects_list;
old_lex->all_selects_list->link_prev= &end->link_next; old_lex->all_selects_list->link_prev= &end->link_next;
old_lex->all_selects_list= lex->all_selects_list; old_lex->all_selects_list= lex->all_selects_list;
@ -946,24 +981,26 @@ frm_type_enum mysql_frm_type(char *path)
bool check_key_in_view(THD *thd, TABLE_LIST *view) bool check_key_in_view(THD *thd, TABLE_LIST *view)
{ {
TABLE *table; TABLE *table;
Item **trans; Field_translator *trans;
KEY *key_info, *key_info_end; KEY *key_info, *key_info_end;
uint i, elements_in_view; uint i, elements_in_view;
DBUG_ENTER("check_key_in_view"); DBUG_ENTER("check_key_in_view");
/* /*
we do not support updatable UNIONs in VIW, so we can check just limit of we do not support updatable UNIONs in VIEW, so we can check just limit of
LEX::select_lex LEX::select_lex
*/ */
if (!view->view || thd->lex->sql_command == SQLCOM_INSERT || if ((!view->view && !view->belong_to_view) || thd->lex->sql_command == SQLCOM_INSERT ||
thd->lex->select_lex.select_limit == HA_POS_ERROR) thd->lex->select_lex.select_limit == HA_POS_ERROR)
DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */ DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
table= view->table; table= view->table;
if (view->belong_to_view)
view= view->belong_to_view;
trans= view->field_translation; trans= view->field_translation;
key_info_end= (key_info= table->key_info)+ table->keys; key_info_end= (key_info= table->key_info)+ table->keys;
elements_in_view= view->view->select_lex.item_list.elements; elements_in_view= view->view->select_lex.item_list.elements;
DBUG_ASSERT(view->table != 0 && view->field_translation != 0); DBUG_ASSERT(table != 0 && view->field_translation != 0);
/* Loop over all keys to see if a unique-not-null key is used */ /* Loop over all keys to see if a unique-not-null key is used */
for (;key_info != key_info_end ; key_info++) for (;key_info != key_info_end ; key_info++)
@ -980,7 +1017,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
for (k= 0; k < elements_in_view; k++) for (k= 0; k < elements_in_view; k++)
{ {
Item_field *field; Item_field *field;
if ((field= trans[k]->filed_for_view_update()) && if ((field= trans[k].item->filed_for_view_update()) &&
field->field == key_part->field) field->field == key_part->field)
break; break;
} }
@ -1001,7 +1038,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
for (i= 0; i < elements_in_view; i++) for (i= 0; i < elements_in_view; i++)
{ {
Item_field *field; Item_field *field;
if ((field= trans[i]->filed_for_view_update()) && if ((field= trans[i].item->filed_for_view_update()) &&
field->field == *field_ptr) field->field == *field_ptr)
break; break;
} }
@ -1035,24 +1072,33 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
insert_view_fields() insert_view_fields()
list list for insertion list list for insertion
view view for processing view view for processing
RETURN
0 - OK
-1 - error (is not sent to cliet)
*/ */
void insert_view_fields(List<Item> *list, TABLE_LIST *view) int insert_view_fields(List<Item> *list, TABLE_LIST *view)
{ {
uint elements_in_view= view->view->select_lex.item_list.elements; uint elements_in_view= view->view->select_lex.item_list.elements;
Item **trans; Field_translator *trans;
DBUG_ENTER("insert_view_fields"); DBUG_ENTER("insert_view_fields");
if (!(trans= view->field_translation)) if (!(trans= view->field_translation))
DBUG_VOID_RETURN; DBUG_RETURN(0);
for (uint i= 0; i < elements_in_view; i++) for (uint i= 0; i < elements_in_view; i++)
{ {
Item_field *fld; Item_field *fld;
if ((fld= trans[i]->filed_for_view_update())) if ((fld= trans[i].item->filed_for_view_update()))
list->push_back(fld); list->push_back(fld);
else
{
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "INSERT");
DBUG_RETURN(-1);
}
} }
DBUG_VOID_RETURN; DBUG_RETURN(0);
} }
/* /*

View File

@ -25,7 +25,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *view, enum_drop_mode drop_mode);
bool check_key_in_view(THD *thd, TABLE_LIST * view); bool check_key_in_view(THD *thd, TABLE_LIST * view);
void insert_view_fields(List<Item> *list, TABLE_LIST *view); int insert_view_fields(List<Item> *list, TABLE_LIST *view);
frm_type_enum mysql_frm_type(char *path); frm_type_enum mysql_frm_type(char *path);

View File

@ -1517,11 +1517,68 @@ void st_table_list::calc_md5(char *buffer)
void st_table_list::set_ancestor() void st_table_list::set_ancestor()
{ {
if (ancestor->ancestor) /* process all tables of view */
ancestor->set_ancestor(); for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
table= ancestor->table; {
schema_table= ancestor->schema_table; if (tbl->ancestor)
ancestor->table->grant= grant; ancestor->set_ancestor();
tbl->table->grant= grant;
}
/* if view contain only one table, substitute TABLE of it */
if (!ancestor->next_local)
{
table= ancestor->table;
schema_table= ancestor->schema_table;
}
}
/*
Save old want_privilege and clear want_privilege
SYNOPSIS
save_and_clear_want_privilege()
*/
void st_table_list::save_and_clear_want_privilege()
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
{
privilege_backup= tbl->table->grant.want_privilege;
tbl->table->grant.want_privilege= 0;
}
else
{
DBUG_ASSERT(tbl->view && tbl->ancestor &&
tbl->ancestor->next_local);
tbl->save_and_clear_want_privilege();
}
}
}
/*
restore want_privilege saved by save_and_clear_want_privilege
SYNOPSIS
restore_want_privilege()
*/
void st_table_list::restore_want_privilege()
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
tbl->table->grant.want_privilege= privilege_backup;
else
{
DBUG_ASSERT(tbl->view && tbl->ancestor &&
tbl->ancestor->next_local);
tbl->restore_want_privilege();
}
}
} }
@ -1551,10 +1608,11 @@ void st_table_list::set_ancestor()
bool st_table_list::setup_ancestor(THD *thd, Item **conds, bool st_table_list::setup_ancestor(THD *thd, Item **conds,
uint8 check_opt_type) uint8 check_opt_type)
{ {
Item **transl; Field_translator *transl;
SELECT_LEX *select= &view->select_lex; SELECT_LEX *select= &view->select_lex;
SELECT_LEX *current_select_save= thd->lex->current_select; SELECT_LEX *current_select_save= thd->lex->current_select;
Item *item; Item *item;
TABLE_LIST *tbl;
List_iterator_fast<Item> it(select->item_list); List_iterator_fast<Item> it(select->item_list);
uint i= 0; uint i= 0;
bool save_set_query_id= thd->set_query_id; bool save_set_query_id= thd->set_query_id;
@ -1562,38 +1620,57 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
bool save_allow_sum_func= thd->allow_sum_func; bool save_allow_sum_func= thd->allow_sum_func;
DBUG_ENTER("st_table_list::setup_ancestor"); DBUG_ENTER("st_table_list::setup_ancestor");
if (ancestor->ancestor && for (tbl= ancestor; tbl; tbl= tbl->next_local)
ancestor->setup_ancestor(thd, conds, {
(check_opt_type == VIEW_CHECK_CASCADED ? if (tbl->ancestor &&
VIEW_CHECK_CASCADED : tbl->setup_ancestor(thd, conds,
VIEW_CHECK_NONE))) (check_opt_type == VIEW_CHECK_CASCADED ?
DBUG_RETURN(1); VIEW_CHECK_CASCADED :
VIEW_CHECK_NONE)))
DBUG_RETURN(1);
}
if (field_translation) if (field_translation)
{ {
/* prevent look up in SELECTs tree */ /* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex; thd->lex->current_select= &thd->lex->select_lex;
thd->lex->select_lex.no_wrap_view_item= 1;
thd->set_query_id= 1; thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */ /* this view was prepared already on previous PS/SP execution */
Item **end= field_translation + select->item_list.elements; Field_translator *end= field_translation + select->item_list.elements;
for (Item **item= field_translation; item < end; item++) /* real rights will be checked in VIEW field */
save_and_clear_want_privilege();
/* aggregate function are allowed */
thd->allow_sum_func= 1;
for (transl= field_translation; transl < end; transl++)
{ {
/* TODO: fix for several tables in VIEW */ if (!transl->item->fixed &&
uint want_privilege= ancestor->table->grant.want_privilege; transl->item->fix_fields(thd, ancestor, &transl->item))
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */
thd->allow_sum_func= 1;
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
goto err; goto err;
ancestor->table->grant.want_privilege= want_privilege; }
for (tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->on_expr && !tbl->on_expr->fixed &&
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
goto err;
}
if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
goto err;
restore_want_privilege();
/* WHERE/ON resolved => we can rename fields */
for (transl= field_translation; transl < end; transl++)
{
transl->item->rename((char *)transl->name);
} }
goto ok; goto ok;
} }
/* view fields translation table */ /* view fields translation table */
if (!(transl= if (!(transl=
(Item**)(thd->current_arena->alloc(select->item_list.elements * sizeof(Item*))))) (Field_translator*)(thd->current_arena->
alloc(select->item_list.elements *
sizeof(Field_translator)))))
{ {
DBUG_RETURN(1); DBUG_RETURN(1);
} }
@ -1609,22 +1686,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
used fields correctly. used fields correctly.
*/ */
thd->set_query_id= 1; thd->set_query_id= 1;
/* real rights will be checked in VIEW field */
save_and_clear_want_privilege();
/* aggregate function are allowed */
thd->allow_sum_func= 1;
while ((item= it++)) while ((item= it++))
{ {
/* TODO: fix for several tables in VIEW */ /* save original name of view column */
uint want_privilege= ancestor->table->grant.want_privilege; char *name= item->name;
/* real rights will be checked in VIEW field */
ancestor->table->grant.want_privilege= 0;
/* aggregate function are allowed */
thd->allow_sum_func= 1;
if (!item->fixed && item->fix_fields(thd, ancestor, &item)) if (!item->fixed && item->fix_fields(thd, ancestor, &item))
goto err; goto err;
ancestor->table->grant.want_privilege= want_privilege; /* set new item get in fix fields and original column name */
transl[i++]= item; transl[i].name= name;
transl[i++].item= item;
} }
field_translation= transl; field_translation= transl;
/* TODO: sort this list? Use hash for big number of fields */ /* TODO: sort this list? Use hash for big number of fields */
for (tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->on_expr && !tbl->on_expr->fixed &&
tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
goto err;
}
if (where || if (where ||
(check_opt_type == VIEW_CHECK_CASCADED && (check_opt_type == VIEW_CHECK_CASCADED &&
ancestor->check_option)) ancestor->check_option))
@ -1697,6 +1781,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
if (arena) if (arena)
thd->restore_backup_item_arena(arena, &backup); thd->restore_backup_item_arena(arena, &backup);
} }
restore_want_privilege();
/* /*
fix_fields do not need tables, because new are only AND operation and we fix_fields do not need tables, because new are only AND operation and we
just need recollect statistics just need recollect statistics
@ -1705,6 +1791,15 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
check_option->fix_fields(thd, 0, &check_option)) check_option->fix_fields(thd, 0, &check_option))
goto err; goto err;
/* WHERE/ON resolved => we can rename fields */
{
Field_translator *end= field_translation + select->item_list.elements;
for (transl= field_translation; transl < end; transl++)
{
transl->item->rename((char *)transl->name);
}
}
/* full text function moving to current select */ /* full text function moving to current select */
if (view->select_lex.ftfunc_list->elements) if (view->select_lex.ftfunc_list->elements)
{ {
@ -1749,9 +1844,10 @@ void st_table_list::cleanup_items()
if (!field_translation) if (!field_translation)
return; return;
Item **end= field_translation + view->select_lex.item_list.elements; Field_translator *end= (field_translation +
for (Item **item= field_translation; item < end; item++) view->select_lex.item_list.elements);
(*item)->walk(&Item::cleanup_processor, 0); for (Field_translator *transl= field_translation; transl < end; transl++)
transl->item->walk(&Item::cleanup_processor, 0);
} }
@ -1789,6 +1885,96 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
} }
/*
Find table in underlaying tables by mask and check that only this
table belong to given mask
SYNOPSIS
st_table_list::check_single_table()
table reference on variable where to store found table
(should be 0 on call, to find table, or point to table for
unique test)
map bit mask of tables
RETURN
FALSE table not found or found only one
TRUE found several tables
*/
bool st_table_list::check_single_table(st_table_list **table, table_map map)
{
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
{
if (tbl->table)
{
if (tbl->table->map & map)
{
if (*table)
return TRUE;
else
*table= tbl;
}
}
else
if (tbl->check_single_table(table, map))
return TRUE;
}
return FALSE;
}
/*
Set insert_values buffer
SYNOPSIS
set_insert_values()
mem_root memory pool for allocating
RETURN
FALSE - OK
TRUE - out of memory
*/
bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
{
if (table)
{
if (!table->insert_values &&
!(table->insert_values= (byte *)alloc_root(mem_root,
table->rec_buff_length)))
return TRUE;
}
else
{
DBUG_ASSERT(view && ancestor && ancestor->next_local);
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
if (tbl->set_insert_values(mem_root))
return TRUE;
}
return FALSE;
}
/*
clear insert_values reference
SYNOPSIS
clear_insert_values()
*/
void st_table_list::clear_insert_values()
{
if (table)
table->insert_values= 0;
else
{
DBUG_ASSERT(view && ancestor && ancestor->next_local);
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
tbl->clear_insert_values();
}
}
void Field_iterator_view::set(TABLE_LIST *table) void Field_iterator_view::set(TABLE_LIST *table)
{ {
ptr= table->field_translation; ptr= table->field_translation;
@ -1810,7 +1996,7 @@ Item *Field_iterator_table::item(THD *thd)
const char *Field_iterator_view::name() const char *Field_iterator_view::name()
{ {
return (*ptr)->name; return ptr->name;
} }

View File

@ -274,6 +274,11 @@ typedef struct st_schema_table
struct st_lex; struct st_lex;
class select_union; class select_union;
struct Field_translator
{
Item *item;
const char *name;
};
typedef struct st_table_list typedef struct st_table_list
{ {
@ -308,11 +313,13 @@ typedef struct st_table_list
/* link to select_lex where this table was used */ /* link to select_lex where this table was used */
st_select_lex *select_lex; st_select_lex *select_lex;
st_lex *view; /* link on VIEW lex for merging */ st_lex *view; /* link on VIEW lex for merging */
Item **field_translation; /* array of VIEW fields */ Field_translator *field_translation; /* array of VIEW fields */
/* ancestor of this table (VIEW merge algorithm) */ /* ancestor of this table (VIEW merge algorithm) */
st_table_list *ancestor; st_table_list *ancestor;
/* most upper view this table belongs to */ /* most upper view this table belongs to */
st_table_list *belong_to_view; st_table_list *belong_to_view;
/* list of join table tree leaves */
st_table_list *next_leaf;
Item *where; /* VIEW WHERE clause condition */ Item *where; /* VIEW WHERE clause condition */
Item *check_option; /* WITH CHECK OPTION condition */ Item *check_option; /* WITH CHECK OPTION condition */
LEX_STRING query; /* text of (CRETE/SELECT) statement */ LEX_STRING query; /* text of (CRETE/SELECT) statement */
@ -332,6 +339,7 @@ typedef struct st_table_list
*/ */
uint8 effective_with_check; uint8 effective_with_check;
uint effective_algorithm; /* which algorithm was really used */ uint effective_algorithm; /* which algorithm was really used */
uint privilege_backup; /* place for saving privileges */
GRANT_INFO grant; GRANT_INFO grant;
thr_lock_type lock_type; thr_lock_type lock_type;
uint outer_join; /* Which join type */ uint outer_join; /* Which join type */
@ -366,6 +374,11 @@ typedef struct st_table_list
void cleanup_items(); void cleanup_items();
bool placeholder() {return derived || view; } bool placeholder() {return derived || view; }
void print(THD *thd, String *str); void print(THD *thd, String *str);
void save_and_clear_want_privilege();
void restore_want_privilege();
bool check_single_table(st_table_list **table, table_map map);
bool set_insert_values(MEM_ROOT *mem_root);
void clear_insert_values();
} TABLE_LIST; } TABLE_LIST;
class Item; class Item;
@ -400,14 +413,14 @@ public:
class Field_iterator_view: public Field_iterator class Field_iterator_view: public Field_iterator
{ {
Item **ptr, **array_end; Field_translator *ptr, *array_end;
public: public:
Field_iterator_view() :ptr(0), array_end(0) {} Field_iterator_view() :ptr(0), array_end(0) {}
void set(TABLE_LIST *table); void set(TABLE_LIST *table);
void next() { ptr++; } void next() { ptr++; }
bool end_of_fields() { return ptr == array_end; } bool end_of_fields() { return ptr == array_end; }
const char *name(); const char *name();
Item *item(THD *thd) { return *ptr; } Item *item(THD *thd) { return ptr->item; }
Field *field() { return 0; } Field *field() { return 0; }
}; };