mirror of
https://github.com/MariaDB/server.git
synced 2025-06-22 08:22:01 +03:00
merge
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:
@ -409,4 +409,7 @@
|
||||
#define ER_PS_MANY_PARAM 1390
|
||||
#define ER_KEY_PART_0 1391
|
||||
#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
|
||||
|
@ -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 v2 (y) as select x from v1 where x < 100;
|
||||
select * from v2;
|
||||
x
|
||||
y
|
||||
2
|
||||
3
|
||||
drop table t1;
|
||||
@ -1661,3 +1661,199 @@ check table v1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.v1 check error View 'test.v1' references invalid table(s) or column(s)
|
||||
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;
|
||||
|
@ -1599,3 +1599,120 @@ check table v1,t1;
|
||||
drop table t1;
|
||||
check table 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;
|
||||
|
30
sql/item.cc
30
sql/item.cc
@ -46,12 +46,11 @@ void item_init(void)
|
||||
}
|
||||
|
||||
Item::Item():
|
||||
name_length(0), fixed(0),
|
||||
name(0), orig_name(0), name_length(0), fixed(0),
|
||||
collation(default_charset(), DERIVATION_COERCIBLE)
|
||||
{
|
||||
marker= 0;
|
||||
maybe_null=null_value=with_sum_func=unsigned_flag=0;
|
||||
name= 0;
|
||||
decimals= 0; max_length= 0;
|
||||
|
||||
/* 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):
|
||||
str_value(item->str_value),
|
||||
name(item->name),
|
||||
orig_name(item->orig_name),
|
||||
max_length(item->max_length),
|
||||
marker(item->marker),
|
||||
decimals(item->decimals),
|
||||
@ -111,10 +111,12 @@ void Item::print_item_w_name(String *str)
|
||||
void Item::cleanup()
|
||||
{
|
||||
DBUG_ENTER("Item::cleanup");
|
||||
DBUG_PRINT("info", ("Item: 0x%lx", this));
|
||||
DBUG_PRINT("info", ("Type: %d", (int)type()));
|
||||
DBUG_PRINT("info", ("Item: 0x%lx, Type: %d, name %s, original name %s",
|
||||
this, (int)type(), name, orig_name));
|
||||
fixed=0;
|
||||
marker= 0;
|
||||
if (orig_name)
|
||||
name= orig_name;
|
||||
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,
|
||||
const char *field_name_par)
|
||||
:orig_db_name(db_name_par), orig_table_name(table_name_par),
|
||||
|
@ -139,6 +139,8 @@ public:
|
||||
*/
|
||||
String str_value;
|
||||
my_string name; /* Name from select */
|
||||
/* Original item name (if it was renamed)*/
|
||||
my_string orig_name;
|
||||
Item *next;
|
||||
uint32 max_length;
|
||||
uint name_length; /* Length of name */
|
||||
@ -166,6 +168,7 @@ public:
|
||||
name=0;
|
||||
} /*lint -e1509 */
|
||||
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);
|
||||
virtual void cleanup();
|
||||
virtual void make_field(Send_field *field);
|
||||
|
@ -959,7 +959,8 @@ public:
|
||||
void update_used_tables();
|
||||
void print(String *str);
|
||||
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 copy_andor_arguments(THD *thd, Item_cond *item);
|
||||
bool walk(Item_processor processor, byte *arg);
|
||||
|
@ -1422,7 +1422,7 @@ void subselect_uniquesubquery_engine::exclude()
|
||||
table_map subselect_engine::calc_const_tables(TABLE_LIST *table)
|
||||
{
|
||||
table_map map= 0;
|
||||
for(; table; table= table->next_local)
|
||||
for(; table; table= table->next_leaf)
|
||||
{
|
||||
TABLE *tbl= table->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()
|
||||
{
|
||||
return calc_const_tables((TABLE_LIST *) select_lex->outer_select()->
|
||||
table_list.first);
|
||||
leaf_tables);
|
||||
}
|
||||
|
||||
|
||||
table_map subselect_union_engine::upper_select_const_tables()
|
||||
{
|
||||
return calc_const_tables((TABLE_LIST *) unit->outer_select()->
|
||||
table_list.first);
|
||||
return calc_const_tables((TABLE_LIST *) unit->outer_select()->leaf_tables);
|
||||
}
|
||||
|
||||
|
||||
|
@ -668,7 +668,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
uint length, Item **ref,
|
||||
bool check_grants_table, bool check_grants_view,
|
||||
bool allow_rowid,
|
||||
uint *cached_field_index_ptr);
|
||||
uint *cached_field_index_ptr,
|
||||
bool register_tree_change);
|
||||
Field *
|
||||
find_field_in_real_table(THD *thd, TABLE *table, const char *name,
|
||||
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,
|
||||
List_iterator<Item> *it, bool any_privileges,
|
||||
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,
|
||||
List<Item> *sum_func_list, uint wild_num);
|
||||
bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
|
||||
List<Item> &item, bool set_query_id,
|
||||
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 init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
|
||||
void wait_for_refresh(THD *thd);
|
||||
|
@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
|
||||
|
||||
SYNOPSIS
|
||||
opt_sum_query()
|
||||
tables Tables in query
|
||||
all_fields All fields to be returned
|
||||
conds WHERE clause
|
||||
tables list of leaves of join table tree
|
||||
all_fields All fields to be returned
|
||||
conds WHERE clause
|
||||
|
||||
NOTE:
|
||||
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();
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -128,7 +128,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
{
|
||||
longlong count= 1;
|
||||
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() &
|
||||
HA_NOT_EXACT_COUNT) || table->schema_table)
|
||||
|
@ -421,3 +421,6 @@ character-set=latin2
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -412,3 +412,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -421,3 +421,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -414,3 +414,6 @@ character-set=latin7
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -422,3 +422,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=greek
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -414,3 +414,6 @@ character-set=latin2
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -413,3 +413,6 @@ character-set=ujis
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=euckr
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -411,3 +411,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -411,3 +411,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -414,3 +414,6 @@ character-set=latin2
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -411,3 +411,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -414,3 +414,6 @@ character-set=latin2
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -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> <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><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>"
|
||||
"Can't drop a %s from within another stored routine"
|
||||
"GOTO is not allowed in a stored procedure handler"
|
||||
@ -414,3 +414,6 @@ character-set=koi8r
|
||||
"Prepared statement contains too many placeholders"
|
||||
"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> <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'"
|
||||
|
@ -402,3 +402,6 @@ character-set=cp1250
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -417,3 +417,6 @@ character-set=latin2
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -413,3 +413,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -409,3 +409,6 @@ character-set=latin1
|
||||
"Prepared statement contains too many placeholders"
|
||||
"Key part '%-.64s' length cannot be 0"
|
||||
"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'"
|
||||
|
@ -415,3 +415,6 @@ character-set=koi8u
|
||||
"Prepared statement contains too many placeholders"
|
||||
"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><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>"
|
||||
|
@ -575,6 +575,7 @@ db_show_routine_status(THD *thd, int type, const char *wild)
|
||||
Item *item;
|
||||
List<Item> field_list;
|
||||
struct st_used_field *used_field;
|
||||
TABLE_LIST *leaves= 0;
|
||||
st_used_field used_fields[array_elements(init_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
|
||||
*/
|
||||
setup_tables(thd, &tables, 0);
|
||||
setup_tables(thd, &tables, 0, &leaves, 0);
|
||||
for (used_field= &used_fields[0];
|
||||
used_field->field_name;
|
||||
used_field++)
|
||||
|
@ -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(),
|
||||
column->column.ptr(),
|
||||
column->column.length(), 0, 0, 0, 0,
|
||||
&unused_field_idx))
|
||||
&unused_field_idx, FALSE))
|
||||
{
|
||||
my_error(ER_BAD_FIELD_ERROR, MYF(0),
|
||||
column->column.c_ptr(), table_list->alias);
|
||||
|
229
sql/sql_base.cc
229
sql/sql_base.cc
@ -557,10 +557,10 @@ void close_temporary_tables(THD *thd)
|
||||
|
||||
SYNOPSIS
|
||||
find_table_in_list()
|
||||
table Pointer to table list
|
||||
table Pointer to table list
|
||||
offset Offset to which list in table structure to use
|
||||
db_name Data base name
|
||||
table_name Table name
|
||||
db_name Data base name
|
||||
table_name Table name
|
||||
|
||||
NOTES:
|
||||
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))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
table->table->table_cache_key && // it is not temporary table
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_cache_key, db_name) &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_name, table_name)))
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_cache_key, db_name) &&
|
||||
!my_strcasecmp(table_alias_charset,
|
||||
table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -595,12 +595,12 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view && // it is VIEW and
|
||||
table->table->table_cache_key && // it is not temporary table
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name)))
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!strcmp(table->db, db_name) &&
|
||||
!strcmp(table->real_name, table_name)) ||
|
||||
(table->view &&
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2072,6 +2072,8 @@ Field *view_ref_found= (Field*) 0x2;
|
||||
allow_rowid do allow finding of "_rowid" field?
|
||||
cached_field_index_ptr cached position in field list (used to
|
||||
speedup prepared tables field finding)
|
||||
register_tree_change TRUE if ref is not stack variable and we
|
||||
need register changes in item tree
|
||||
|
||||
RETURN
|
||||
0 field is not found
|
||||
@ -2085,17 +2087,21 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
uint length, Item **ref,
|
||||
bool check_grants_table, bool check_grants_view,
|
||||
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;
|
||||
if (table_list->field_translation)
|
||||
{
|
||||
DBUG_ASSERT(ref != 0 && table_list->view != 0);
|
||||
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 ++)
|
||||
{
|
||||
if (strcmp(trans[i]->name, name) == 0)
|
||||
if (strcmp(trans[i].name, name) == 0)
|
||||
{
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
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_name.str,
|
||||
name, length))
|
||||
return WRONG_GRANT;
|
||||
DBUG_RETURN(WRONG_GRANT);
|
||||
#endif
|
||||
if (thd->lex->current_select->no_wrap_view_item)
|
||||
*ref= trans[i];
|
||||
*ref= trans[i].item;
|
||||
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);
|
||||
/* 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);
|
||||
(*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,
|
||||
check_grants_table, allow_rowid,
|
||||
@ -2135,10 +2142,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
table_list->view_name.str,
|
||||
name, length))
|
||||
{
|
||||
return WRONG_GRANT;
|
||||
DBUG_RETURN(WRONG_GRANT);
|
||||
}
|
||||
#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
|
||||
accept this trade off.
|
||||
*/
|
||||
found= find_field_in_real_table(thd, item->cached_table->table,
|
||||
name, length,
|
||||
test(item->cached_table->
|
||||
table->grant.want_privilege) &&
|
||||
check_privileges,
|
||||
1, &(item->cached_field_index));
|
||||
if (item->cached_table->table)
|
||||
{
|
||||
found= find_field_in_real_table(thd, item->cached_table->table,
|
||||
name, length,
|
||||
test(item->cached_table->
|
||||
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 == WRONG_GRANT)
|
||||
return (Field*) 0;
|
||||
return (Field*) 0;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
@ -2312,12 +2336,14 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
found_table=1;
|
||||
Field *find= find_field_in_table(thd, tables, name, item->name,
|
||||
length, ref,
|
||||
(test(tables->table->grant.
|
||||
(tables->table &&
|
||||
test(tables->table->grant.
|
||||
want_privilege) &&
|
||||
check_privileges),
|
||||
(test(tables->grant.want_privilege) &&
|
||||
check_privileges),
|
||||
1, &(item->cached_field_index));
|
||||
1, &(item->cached_field_index),
|
||||
TRUE);
|
||||
if (find)
|
||||
{
|
||||
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
|
||||
for (; tables ; tables= tables->next_local)
|
||||
{
|
||||
if (!tables->table)
|
||||
if (!tables->table && !tables->ancestor)
|
||||
{
|
||||
if (report_error == REPORT_ALL_ERRORS ||
|
||||
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,
|
||||
length, ref,
|
||||
(test(tables->table->grant.
|
||||
(tables->table &&
|
||||
test(tables->table->grant.
|
||||
want_privilege) &&
|
||||
check_privileges),
|
||||
(test(tables->grant.want_privilege) &&
|
||||
check_privileges),
|
||||
allow_rowid, &(item->cached_field_index));
|
||||
allow_rowid,
|
||||
&(item->cached_field_index),
|
||||
TRUE);
|
||||
if (field)
|
||||
{
|
||||
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()) ||
|
||||
(item= *(it.ref()))->check_cols(1))
|
||||
{
|
||||
select_lex->no_wrap_view_item= 0;
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
}
|
||||
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
|
||||
|
||||
@ -2731,11 +2789,14 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
thd Thread handler
|
||||
tables Table list
|
||||
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
|
||||
Remap table numbers if INSERT ... SELECT
|
||||
Check also that the 'used keys' and 'ignored keys' exists and set up the
|
||||
table structure accordingly
|
||||
Create leaf tables list
|
||||
|
||||
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.
|
||||
@ -2745,16 +2806,23 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
|
||||
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");
|
||||
if (!tables || tables->setup_is_done)
|
||||
DBUG_RETURN(0);
|
||||
tables->setup_is_done= 1;
|
||||
|
||||
if (!(*leaves))
|
||||
{
|
||||
make_leaves_list(leaves, tables);
|
||||
}
|
||||
|
||||
uint tablenr=0;
|
||||
for (TABLE_LIST *table_list= tables;
|
||||
for (TABLE_LIST *table_list= *leaves;
|
||||
table_list;
|
||||
table_list= table_list->next_local, tablenr++)
|
||||
table_list= table_list->next_leaf, tablenr++)
|
||||
{
|
||||
TABLE *table= table_list->table;
|
||||
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->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)
|
||||
{
|
||||
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2889,9 +2965,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
tables->alias) &&
|
||||
(!db_name || !strcmp(tables->db,db_name))))
|
||||
{
|
||||
bool view;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
/* 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)
|
||||
{
|
||||
@ -2904,6 +2983,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
else if (!tables->schema_table)
|
||||
{
|
||||
DBUG_ASSERT(table != 0);
|
||||
table_iter.set(tables);
|
||||
if (check_grant_all_columns(thd, SELECT_ACL, &table->grant,
|
||||
table->table_cache_key, table->real_name,
|
||||
@ -2912,8 +2992,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
}
|
||||
#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;
|
||||
thd->used_tables|= table->map;
|
||||
last= embedded= tables;
|
||||
|
||||
while ((embedding= embedded->embedding) &&
|
||||
@ -2940,9 +3029,15 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
natural_join_table= embedding;
|
||||
}
|
||||
if (tables->field_translation)
|
||||
{
|
||||
iterator= &view_iter;
|
||||
view= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iterator= &table_iter;
|
||||
view= 0;
|
||||
}
|
||||
iterator->set(tables);
|
||||
|
||||
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,
|
||||
field_name,
|
||||
strlen(field_name), ¬_used_item, 0, 0, 0,
|
||||
¬_used_field_index))
|
||||
¬_used_field_index, TRUE))
|
||||
{
|
||||
Item *item= iterator->item(thd);
|
||||
if (!found++)
|
||||
(void) it->replace(item); // Replace '*'
|
||||
else
|
||||
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
|
||||
if (any_privileges)
|
||||
{
|
||||
@ -3026,8 +3126,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
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)
|
||||
@ -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;
|
||||
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 */
|
||||
for (table= tables; table; table= table->next_local)
|
||||
for (table= leaves; table; table= table->next_leaf)
|
||||
{
|
||||
TABLE_LIST *embedded;
|
||||
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 *iterator;
|
||||
Field *t1_field, *t2_field;
|
||||
Item *item_t2;
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
Item *item_t2= 0;
|
||||
Item_cond_and *cond_and= new Item_cond_and();
|
||||
|
||||
if (!cond_and) // If not out of memory
|
||||
goto err_no_arena;
|
||||
@ -3165,7 +3275,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
t1_field_name,
|
||||
strlen(t1_field_name), &item_t2,
|
||||
0, 0, 0,
|
||||
¬_used_field_index)))
|
||||
¬_used_field_index,
|
||||
FALSE)))
|
||||
{
|
||||
if (t2_field != view_ref_found)
|
||||
{
|
||||
|
@ -1650,7 +1650,9 @@ public:
|
||||
|
||||
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;
|
||||
TABLE **tmp_tables, *main_table, *table_to_update;
|
||||
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;
|
||||
|
||||
public:
|
||||
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
|
||||
List<Item> *values, enum_duplicates handle_duplicates);
|
||||
multi_update(THD *thd_arg, TABLE_LIST *ut, TABLE_LIST *leaves_list,
|
||||
List<Item> *fields, List<Item> *values,
|
||||
enum_duplicates handle_duplicates);
|
||||
~multi_update();
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_data(List<Item> &items);
|
||||
|
@ -44,7 +44,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
||||
|
||||
if (open_and_lock_tables(thd, table_list))
|
||||
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);
|
||||
thd->proc_info="init";
|
||||
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;
|
||||
DBUG_ENTER("mysql_prepare_delete");
|
||||
|
||||
if (setup_tables(thd, table_list, conds) ||
|
||||
setup_conds(thd, table_list, conds) ||
|
||||
if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
|
||||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
|
||||
setup_ftfuncs(select_lex))
|
||||
DBUG_RETURN(TRUE);
|
||||
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
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Fix tables-to-be-deleted-from list to point at opened tables */
|
||||
|
@ -618,6 +618,7 @@ bool mysqld_help(THD *thd, const char *mask)
|
||||
st_find_field used_fields[array_elements(init_used_fields)];
|
||||
DBUG_ENTER("mysqld_help");
|
||||
|
||||
TABLE_LIST *leaves= 0;
|
||||
TABLE_LIST tables[4];
|
||||
bzero((gptr)tables,sizeof(tables));
|
||||
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
|
||||
*/
|
||||
setup_tables(thd, tables, 0);
|
||||
setup_tables(thd, tables, 0, &leaves, 0);
|
||||
memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
|
||||
if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
|
||||
goto error;
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "sql_acl.h"
|
||||
#include "sp_head.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
static int check_null_fields(THD *thd,TABLE *entry);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -31,6 +32,7 @@ static void end_delayed_insert(THD *thd);
|
||||
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
|
||||
static void unlink_blobs(register TABLE *table);
|
||||
#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 */
|
||||
|
||||
@ -54,8 +56,22 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
{
|
||||
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 (!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)
|
||||
{
|
||||
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;
|
||||
if (res)
|
||||
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)
|
||||
{
|
||||
@ -107,6 +140,15 @@ check_insert_fields(THD *thd, TABLE_LIST *table_list, List<Item> &fields,
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -131,7 +173,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
ulong counter = 1;
|
||||
ulonglong id;
|
||||
COPY_INFO info;
|
||||
TABLE *table;
|
||||
TABLE *table= 0;
|
||||
List_iterator_fast<List_item> its(values_list);
|
||||
List_item *values;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
@ -197,17 +239,14 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
if (res || thd->is_fatal_error)
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
table= table_list->table;
|
||||
thd->proc_info="init";
|
||||
thd->used_tables=0;
|
||||
values= its++;
|
||||
|
||||
if (duplic == DUP_UPDATE && !table->insert_values)
|
||||
if (duplic == DUP_UPDATE)
|
||||
{
|
||||
/* it should be allocated before Item::fix_fields() */
|
||||
table->insert_values=
|
||||
(byte *)alloc_root(thd->mem_root, table->rec_buff_length);
|
||||
if (!table->insert_values)
|
||||
if (table_list->set_insert_values(thd->mem_root))
|
||||
goto abort;
|
||||
}
|
||||
|
||||
@ -215,6 +254,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
update_fields, update_values, duplic))
|
||||
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
|
||||
value_count= values->elements;
|
||||
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);
|
||||
}
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
table_list->clear_insert_values();
|
||||
thd->abort_on_warning= 0;
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
@ -474,7 +516,7 @@ abort:
|
||||
end_delayed_insert(thd);
|
||||
#endif
|
||||
free_underlaid_joins(thd, &thd->lex->select_lex);
|
||||
table->insert_values=0;
|
||||
table_list->clear_insert_values();
|
||||
thd->abort_on_warning= 0;
|
||||
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;
|
||||
TABLE *table= view->table;
|
||||
Item **trans_start= view->field_translation, **trans_end=trans_start+num;
|
||||
Item **trans;
|
||||
Field_translator *trans_start= view->field_translation,
|
||||
*trans_end= trans_start + num;
|
||||
Field_translator *trans;
|
||||
Field **field_ptr= table->field;
|
||||
ulong other_query_id= query_id - 1;
|
||||
DBUG_ENTER("check_key_in_view");
|
||||
@ -519,19 +562,23 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
{
|
||||
Item_field *field;
|
||||
/* 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);
|
||||
if (field->field->unireg_check == Field::NEXT_NUMBER)
|
||||
view->contain_auto_increment= 1;
|
||||
/* prepare unique test */
|
||||
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 */
|
||||
for (trans= trans_start; trans != trans_end; trans++)
|
||||
{
|
||||
/* 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)
|
||||
DBUG_RETURN(TRUE);
|
||||
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)
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -570,33 +617,35 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
where Pointer to where clause
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 ERROR
|
||||
0 ok
|
||||
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)
|
||||
{
|
||||
bool insert_into_view= (table_list->view != 0);
|
||||
DBUG_ENTER("mysql_prepare_insert_check_table");
|
||||
|
||||
if (setup_tables(thd, table_list, where))
|
||||
DBUG_RETURN(1);
|
||||
if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
|
||||
0))
|
||||
DBUG_RETURN(thd->net.report_error ? -1 : 1);
|
||||
|
||||
if (insert_into_view && !fields.elements)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -625,8 +674,9 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
bool res;
|
||||
DBUG_ENTER("mysql_prepare_insert");
|
||||
|
||||
if (mysql_prepare_insert_check_table(thd, table_list, fields, &unused_conds))
|
||||
DBUG_RETURN(-1);
|
||||
if ((res= mysql_prepare_insert_check_table(thd, table_list,
|
||||
fields, &unused_conds)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
if (check_insert_fields(thd, table_list, fields, *values, 1,
|
||||
!insert_into_view) ||
|
||||
@ -1654,6 +1704,10 @@ bool delayed_insert::handle_inserts(void)
|
||||
bool mysql_insert_select_prepare(THD *thd)
|
||||
{
|
||||
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");
|
||||
/*
|
||||
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,
|
||||
lex->field_list,
|
||||
&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);
|
||||
}
|
||||
|
||||
@ -1692,6 +1767,23 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
if (check_insert_fields(thd, table_list, *fields, values, 1,
|
||||
!insert_into_view))
|
||||
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
|
||||
table->next_number_field=table->found_next_number_field;
|
||||
|
@ -150,7 +150,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
|
||||
lex->found_colon= 0;
|
||||
lex->safe_to_cache_query= 1;
|
||||
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->variables_used= 0;
|
||||
lex->select_lex.parent_lex= lex;
|
||||
@ -1049,7 +1049,7 @@ void st_select_lex::init_query()
|
||||
table_list.empty();
|
||||
top_join_list.empty();
|
||||
join_list= &top_join_list;
|
||||
embedding= 0;
|
||||
embedding= leaf_tables= 0;
|
||||
item_list.empty();
|
||||
join= 0;
|
||||
where= prep_where= 0;
|
||||
@ -1644,7 +1644,7 @@ bool st_lex::can_be_merged()
|
||||
select_lex.group_list.elements == 0 &&
|
||||
select_lex.having == 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.select_limit == HA_POS_ERROR);
|
||||
}
|
||||
|
@ -447,6 +447,7 @@ public:
|
||||
List<TABLE_LIST> top_join_list; /* join list of the top level */
|
||||
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
|
||||
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 */
|
||||
|
||||
SQL_LIST order_list; /* ORDER clause */
|
||||
@ -669,6 +670,8 @@ typedef struct st_lex
|
||||
*/
|
||||
TABLE_LIST **query_tables_last;
|
||||
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> ref_list;
|
||||
@ -707,6 +710,7 @@ typedef struct st_lex
|
||||
uint grant, grant_tot_col, which_columns;
|
||||
uint fk_delete_opt, fk_update_opt, fk_match_option;
|
||||
uint slave_thd_opt, start_transaction_opt;
|
||||
uint table_count; /* used when usual update transformed in multiupdate */
|
||||
uint8 describe;
|
||||
uint8 derived_tables;
|
||||
uint8 create_view_algorithm;
|
||||
|
@ -121,9 +121,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
table_list->lock_type= lock_type;
|
||||
if (open_and_lock_tables(thd, table_list))
|
||||
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);
|
||||
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");
|
||||
DBUG_RETURN(TRUE);
|
||||
@ -143,7 +146,8 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
thd->dupp_field=0;
|
||||
/* TODO: use this conds for 'WITH CHECK OPTIONS' */
|
||||
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))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (thd->dupp_field)
|
||||
|
@ -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
|
||||
&select_lex->where) ||
|
||||
&select_lex->where, &select_lex->leaf_tables, 0) ||
|
||||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
|
||||
select_lex->item_list, 1, &all_fields,1) ||
|
||||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
|
||||
|
@ -2882,12 +2882,19 @@ create_error:
|
||||
(ORDER *) select_lex->order_list.first,
|
||||
select_lex->select_limit,
|
||||
lex->duplicates);
|
||||
break;
|
||||
if (res != 2)
|
||||
break;
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
{
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if ((res= multi_update_precheck(thd, all_tables)))
|
||||
break;
|
||||
if (res != 2)
|
||||
{
|
||||
if ((res= multi_update_precheck(thd, all_tables)))
|
||||
break;
|
||||
}
|
||||
else
|
||||
res= 0;
|
||||
|
||||
res= mysql_multi_update(thd, all_tables,
|
||||
&select_lex->item_list,
|
||||
&lex->value_list,
|
||||
@ -2929,35 +2936,28 @@ create_error:
|
||||
|
||||
if (!(res= open_and_lock_tables(thd, all_tables)))
|
||||
{
|
||||
/*
|
||||
Is table which we are changing used somewhere in other parts of
|
||||
query
|
||||
*/
|
||||
if (unique_table(first_table, all_tables->next_global))
|
||||
{
|
||||
/* Using same table for INSERT and SELECT */
|
||||
select_lex->options |= OPTION_BUFFER_RESULT;
|
||||
}
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*)first_table->next_local;
|
||||
|
||||
if ((res= mysql_insert_select_prepare(thd)))
|
||||
break;
|
||||
if ((result= new select_insert(first_table, first_table->table,
|
||||
&lex->field_list, lex->duplicates,
|
||||
lex->duplicates == DUP_IGNORE)))
|
||||
res= mysql_insert_select_prepare(thd);
|
||||
if (!res && (result= new select_insert(first_table, first_table->table,
|
||||
&lex->field_list,
|
||||
lex->duplicates,
|
||||
lex->duplicates == DUP_IGNORE)))
|
||||
{
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*) first_table->next_local;
|
||||
TABLE_LIST *first_select_table;
|
||||
|
||||
/*
|
||||
insert/replace from SELECT give its SELECT_LEX for SELECT,
|
||||
and item_list belong to SELECT
|
||||
*/
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
|
||||
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;
|
||||
delete result;
|
||||
}
|
||||
/* revert changes for SP */
|
||||
lex->select_lex.table_list.first= (byte*) first_table;
|
||||
}
|
||||
else
|
||||
res= TRUE;
|
||||
@ -3012,8 +3012,20 @@ create_error:
|
||||
goto error;
|
||||
|
||||
thd->proc_info="init";
|
||||
if ((res= open_and_lock_tables(thd, all_tables)) ||
|
||||
(res= mysql_multi_delete_prepare(thd)))
|
||||
if ((res= open_and_lock_tables(thd, all_tables)))
|
||||
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;
|
||||
|
||||
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
|
||||
|
@ -935,22 +935,32 @@ error:
|
||||
tables list of tables queries
|
||||
|
||||
RETURN VALUE
|
||||
FALSE success
|
||||
TRUE error
|
||||
0 success
|
||||
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)
|
||||
{
|
||||
bool res;
|
||||
int res;
|
||||
THD *thd= stmt->thd;
|
||||
SELECT_LEX *select= &stmt->lex->select_lex;
|
||||
DBUG_ENTER("mysql_test_update");
|
||||
|
||||
if ((res= update_precheck(thd, table_list)))
|
||||
DBUG_RETURN(res);
|
||||
if (update_precheck(thd, table_list))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
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,
|
||||
&select->where,
|
||||
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;
|
||||
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;
|
||||
}
|
||||
else
|
||||
@ -967,7 +977,7 @@ static bool mysql_test_update(Prepared_statement *stmt,
|
||||
thd->lex->select_lex.no_wrap_view_item= 0;
|
||||
if (setup_fields(thd, 0, table_list,
|
||||
stmt->lex->value_list, 0, 0, 0))
|
||||
res= -1;
|
||||
res= 1;
|
||||
}
|
||||
}
|
||||
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 (!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);
|
||||
lex->unit.cleanup();
|
||||
DBUG_RETURN(FALSE);
|
||||
@ -1195,7 +1214,10 @@ static bool select_like_statement_test(Prepared_statement *stmt,
|
||||
LEX *lex= stmt->lex;
|
||||
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;
|
||||
|
||||
if (specific_prepare && (res= (*specific_prepare)(thd)))
|
||||
@ -1261,6 +1283,7 @@ static int mysql_test_create_table(Prepared_statement *stmt)
|
||||
mysql_test_multiupdate()
|
||||
stmt prepared statemen handler
|
||||
tables list of tables queries
|
||||
converted converted to multi-update from usual update
|
||||
|
||||
RETURN VALUE
|
||||
FALSE success
|
||||
@ -1268,9 +1291,10 @@ static int mysql_test_create_table(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;
|
||||
/*
|
||||
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;
|
||||
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
|
||||
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:
|
||||
res= mysql_test_update(stmt, tables);
|
||||
if (res != 2)
|
||||
break;
|
||||
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
res= mysql_test_multiupdate(stmt, tables, res == 2);
|
||||
break;
|
||||
|
||||
case SQLCOM_DELETE:
|
||||
@ -1433,10 +1474,6 @@ static int check_prepared_statement(Prepared_statement *stmt,
|
||||
case SQLCOM_DELETE_MULTI:
|
||||
res= mysql_test_multidelete(stmt, tables);
|
||||
break;
|
||||
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
res= mysql_test_multiupdate(stmt, tables);
|
||||
break;
|
||||
|
||||
case SQLCOM_INSERT_SELECT:
|
||||
case SQLCOM_REPLACE_SELECT:
|
||||
@ -1720,8 +1757,15 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
|
||||
were closed in the end of previous prepare or execute call.
|
||||
*/
|
||||
tables->table= 0;
|
||||
if (tables->nested_join)
|
||||
tables->nested_join->counter= 0;
|
||||
}
|
||||
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)
|
||||
lex->result->cleanup();
|
||||
|
||||
|
@ -38,7 +38,7 @@ const key_map key_map_empty(0);
|
||||
const key_map key_map_full(~0);
|
||||
|
||||
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);
|
||||
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
|
||||
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,
|
||||
TABLE_LIST *tables,
|
||||
TABLE_LIST *leaves,
|
||||
List<Item> &fields,
|
||||
List<Item> &all_fields,
|
||||
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;
|
||||
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,
|
||||
order) ||
|
||||
setup_group(thd, ref_pointer_array, tables, fields, all_fields,
|
||||
@ -309,13 +310,14 @@ JOIN::prepare(Item ***rref_pointer_array,
|
||||
|
||||
/* 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) ||
|
||||
select_lex->setup_ref_array(thd, og_num) ||
|
||||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
|
||||
&all_fields, 1) ||
|
||||
setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
|
||||
all_fields, &conds, order, group_list,
|
||||
setup_without_group(thd, (*rref_pointer_array), tables_list,
|
||||
select_lex->leaf_tables, fields_list,
|
||||
all_fields, &conds, order, group_list,
|
||||
&hidden_group_fields))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
|
||||
@ -383,7 +385,9 @@ JOIN::prepare(Item ***rref_pointer_array,
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
{
|
||||
@ -585,7 +589,7 @@ JOIN::optimize()
|
||||
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_...
|
||||
*/
|
||||
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)
|
||||
{
|
||||
@ -611,11 +615,11 @@ JOIN::optimize()
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
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 */
|
||||
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)
|
||||
{
|
||||
DBUG_PRINT("error",("Error: make_join_statistics() failed"));
|
||||
@ -1077,7 +1081,7 @@ JOIN::reinit()
|
||||
if (tables_list)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1182,7 +1186,7 @@ JOIN::exec()
|
||||
|
||||
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(),
|
||||
select_options,
|
||||
zero_result_cause,
|
||||
@ -2089,7 +2093,7 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
int error;
|
||||
@ -2119,7 +2123,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
|
||||
|
||||
for (s= stat, i= 0;
|
||||
tables;
|
||||
s++, tables= tables->next_local, i++)
|
||||
s++, tables= tables->next_leaf, i++)
|
||||
{
|
||||
TABLE_LIST *embedding= tables->embedding;
|
||||
stat_vector[i]=s;
|
||||
@ -5078,6 +5082,7 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
|
||||
static void
|
||||
make_outerjoin_info(JOIN *join)
|
||||
{
|
||||
DBUG_ENTER("make_outerjoin_info");
|
||||
for (uint i=join->const_tables ; i < join->tables ; i++)
|
||||
{
|
||||
JOIN_TAB *tab=join->join_tab+i;
|
||||
@ -5121,6 +5126,7 @@ make_outerjoin_info(JOIN *join)
|
||||
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
|
||||
below to check if we should use 'quick' instead.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Item_int"));
|
||||
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
|
||||
the null complemented row.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Item_func_trig_cond"));
|
||||
tmp= new Item_func_trig_cond(tmp,
|
||||
&first_inner_tab->not_null_compl);
|
||||
DBUG_PRINT("info", ("Item_func_trig_cond 0x%lx", (ulong) tmp));
|
||||
if (tmp)
|
||||
tmp->quick_fix_field();
|
||||
/* Add the predicate to other pushed down predicates */
|
||||
DBUG_PRINT("info", ("Item_cond_and"));
|
||||
cond_tab->select_cond= !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)
|
||||
DBUG_RETURN(1);
|
||||
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)
|
||||
{
|
||||
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
|
||||
if (having && having->val_int() == 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();
|
||||
return -2; /* purecov: inspected */
|
||||
}
|
||||
DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond));
|
||||
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)))
|
||||
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)
|
||||
DBUG_RETURN(0); // More than one table
|
||||
DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
|
||||
|
@ -86,25 +86,47 @@ static bool check_fields(THD *thd, List<Item> &items)
|
||||
}
|
||||
|
||||
|
||||
bool 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)
|
||||
/*
|
||||
Process usual UPDATE
|
||||
|
||||
SYNOPSIS
|
||||
mysql_update()
|
||||
thd thread handler
|
||||
fields fields for update
|
||||
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 safe_update= thd->options & OPTION_SAFE_UPDATES;
|
||||
bool used_key_is_modified, transactional_table, log_delayed;
|
||||
bool ignore_err= (thd->lex->duplicates == DUP_IGNORE);
|
||||
bool res;
|
||||
int res;
|
||||
int error=0;
|
||||
uint used_index;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
uint want_privilege;
|
||||
#endif
|
||||
uint table_count= 0;
|
||||
ulong query_id=thd->query_id, timestamp_query_id;
|
||||
ha_rows updated, found;
|
||||
key_map old_used_keys;
|
||||
@ -117,8 +139,26 @@ bool mysql_update(THD *thd,
|
||||
LINT_INIT(used_index);
|
||||
LINT_INIT(timestamp_query_id);
|
||||
|
||||
if (open_and_lock_tables(thd, table_list))
|
||||
DBUG_RETURN(TRUE);
|
||||
if (open_tables(thd, table_list, &table_count))
|
||||
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";
|
||||
table= table_list->table;
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
@ -134,7 +174,7 @@ bool mysql_update(THD *thd,
|
||||
table->grant.want_privilege);
|
||||
#endif
|
||||
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
|
||||
/*
|
||||
@ -156,16 +196,16 @@ bool mysql_update(THD *thd,
|
||||
res= setup_fields(thd, 0, table_list, fields, 1, 0, 0);
|
||||
select_lex->no_wrap_view_item= 0;
|
||||
if (res)
|
||||
DBUG_RETURN(TRUE); /* purecov: inspected */
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
}
|
||||
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))
|
||||
{
|
||||
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
|
||||
DBUG_RETURN(TRUE);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (table->timestamp_field)
|
||||
{
|
||||
@ -184,7 +224,7 @@ bool mysql_update(THD *thd,
|
||||
if (setup_fields(thd, 0, table_list, values, 0, 0, 0))
|
||||
{
|
||||
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
|
||||
@ -197,10 +237,10 @@ bool mysql_update(THD *thd,
|
||||
free_underlaid_joins(thd, select_lex);
|
||||
if (error)
|
||||
{
|
||||
DBUG_RETURN(TRUE); // Error in where
|
||||
DBUG_RETURN(1); // Error in where
|
||||
}
|
||||
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 (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->abort_on_warning= 0;
|
||||
free_io_cache(table);
|
||||
DBUG_RETURN(error >= 0 || thd->net.report_error);
|
||||
DBUG_RETURN((error >= 0 || thd->net.report_error) ? 1 : 0);
|
||||
|
||||
err:
|
||||
delete select;
|
||||
@ -483,7 +523,7 @@ err:
|
||||
table->file->extra(HA_EXTRA_NO_KEYREAD);
|
||||
}
|
||||
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.alias= table_list->alias;
|
||||
|
||||
if (setup_tables(thd, table_list, conds) ||
|
||||
setup_conds(thd, table_list, conds) ||
|
||||
if (setup_tables(thd, table_list, conds, &select_lex->leaf_tables, 0) ||
|
||||
setup_conds(thd, table_list, select_lex->leaf_tables, conds) ||
|
||||
select_lex->setup_ref_array(thd, order_num) ||
|
||||
setup_order(thd, select_lex->ref_pointer_array,
|
||||
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;
|
||||
List<Item> *fields= &lex->select_lex.item_list;
|
||||
TABLE_LIST *tl;
|
||||
TABLE_LIST *leaves;
|
||||
table_map tables_for_update;
|
||||
int res;
|
||||
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;
|
||||
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
|
||||
DBUG_ENTER("mysql_multi_update_prepare");
|
||||
|
||||
/* open tables and create derived ones, but do not lock and fill them */
|
||||
if (open_tables(thd, table_list, & table_count) ||
|
||||
if ((original_multiupdate && open_tables(thd, table_list, & table_count)) ||
|
||||
mysql_handle_derived(lex, &mysql_derived_prepare))
|
||||
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
|
||||
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
|
||||
We don't check privileges here, becasue then we would get error
|
||||
"UPDATE command denided .. for column N" instead of
|
||||
"Target table ... is not updatable"
|
||||
*/
|
||||
if (!tl->derived)
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
TABLE *table= tl->table;
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
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,
|
||||
if ((lex->select_lex.no_wrap_view_item= 1,
|
||||
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
|
||||
lex->select_lex.no_wrap_view_item= 0,
|
||||
res))
|
||||
@ -638,14 +689,15 @@ bool mysql_multi_update_prepare(THD *thd)
|
||||
/*
|
||||
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_LIST *tlist= tl->belong_to_view?tl->belong_to_view:tl;
|
||||
|
||||
/* 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);
|
||||
// Only set timestamp column if this is not modified
|
||||
/* Only set timestamp column if this is not modified */
|
||||
if (table->timestamp_field &&
|
||||
table->timestamp_field->query_id == thd->query_id)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* now lock and fill tables */
|
||||
if (lock_tables(thd, table_list, table_count))
|
||||
@ -712,7 +781,8 @@ bool mysql_multi_update_prepare(THD *thd)
|
||||
/* undone setup_tables() */
|
||||
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,
|
||||
res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0),
|
||||
lex->select_lex.no_wrap_view_item= 0,
|
||||
@ -739,14 +809,16 @@ bool mysql_multi_update(THD *thd,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
|
||||
{
|
||||
bool res;
|
||||
bool res= FALSE;
|
||||
multi_update *result;
|
||||
DBUG_ENTER("mysql_multi_update");
|
||||
|
||||
if (mysql_multi_update_prepare(thd))
|
||||
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)))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
@ -770,12 +842,14 @@ bool mysql_multi_update(THD *thd,
|
||||
|
||||
|
||||
multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
|
||||
TABLE_LIST *leaves_list,
|
||||
List<Item> *field_list, List<Item> *value_list,
|
||||
enum enum_duplicates handle_duplicates_arg)
|
||||
:all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0),
|
||||
updated(0), found(0), fields(field_list), values(value_list),
|
||||
table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg),
|
||||
do_update(1), trans_safe(0), transactional_tables(1)
|
||||
:all_tables(table_list), leaves(leaves_list), update_tables(0),
|
||||
thd(thd_arg), tmp_tables(0), updated(0), found(0), fields(field_list),
|
||||
values(value_list), table_count(0), copy_field(0),
|
||||
handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
|
||||
transactional_tables(1)
|
||||
{}
|
||||
|
||||
|
||||
@ -822,8 +896,9 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
*/
|
||||
|
||||
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;
|
||||
if (tables_to_update & table->map)
|
||||
{
|
||||
@ -890,10 +965,10 @@ int multi_update::prepare(List<Item> ¬_used_values,
|
||||
which will cause an error when reading a row.
|
||||
(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;
|
||||
if (!(tables_to_update & table->map) &&
|
||||
if (!(tables_to_update & table->map) &&
|
||||
find_table_in_local_list(update_tables, table_ref->db,
|
||||
table_ref->real_name))
|
||||
table->no_cache= 1; // Disable row cache
|
||||
|
110
sql/sql_view.cc
110
sql/sql_view.cc
@ -485,17 +485,24 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
{
|
||||
/* TODO: change here when we will support UNIONs */
|
||||
for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
tbl;
|
||||
tbl= tbl->next_local)
|
||||
{
|
||||
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;
|
||||
break;
|
||||
if (up->outer_join)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
goto loop_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loop_out:
|
||||
/*
|
||||
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;
|
||||
THD *thd= current_thd;
|
||||
LEX *old_lex= thd->lex, *lex;
|
||||
SELECT_LEX *view_select;
|
||||
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;
|
||||
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;
|
||||
{
|
||||
ulong options= thd->options;
|
||||
@ -646,6 +655,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
table);
|
||||
TABLE_LIST *view_tables= lex->query_tables;
|
||||
TABLE_LIST *view_tables_tail= 0;
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
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 &&
|
||||
lex->safe_to_cache_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;
|
||||
|
||||
/*
|
||||
@ -741,9 +751,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
old_lex->can_use_merged()) &&
|
||||
!old_lex->can_not_use_merged())
|
||||
{
|
||||
/*
|
||||
TODO: support multi tables substitutions
|
||||
*/
|
||||
/* lex should contain at least one table */
|
||||
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->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;
|
||||
|
||||
/*
|
||||
move lock type (TODO: should we issue error in case of TMPTABLE
|
||||
algorithm and non-read locking)?
|
||||
Process upper level tables of view. As far as we do noy suport union
|
||||
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 */
|
||||
table->where= lex->select_lex.where;
|
||||
table->where= view_select->where;
|
||||
|
||||
/*
|
||||
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;
|
||||
DBUG_PRINT("info", ("algorithm: TEMPORARY TABLE"));
|
||||
lex->select_lex.linkage= DERIVED_TABLE_TYPE;
|
||||
view_select->linkage= DERIVED_TABLE_TYPE;
|
||||
table->updatable= 0;
|
||||
table->effective_with_check= VIEW_CHECK_NONE;
|
||||
|
||||
/* SELECT tree link */
|
||||
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;
|
||||
}
|
||||
@ -810,7 +845,7 @@ ok:
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
/* 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;
|
||||
old_lex->all_selects_list->link_prev= &end->link_next;
|
||||
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)
|
||||
{
|
||||
TABLE *table;
|
||||
Item **trans;
|
||||
Field_translator *trans;
|
||||
KEY *key_info, *key_info_end;
|
||||
uint i, elements_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
|
||||
*/
|
||||
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)
|
||||
DBUG_RETURN(FALSE); /* it is normal table or query without LIMIT */
|
||||
table= view->table;
|
||||
if (view->belong_to_view)
|
||||
view= view->belong_to_view;
|
||||
trans= view->field_translation;
|
||||
key_info_end= (key_info= table->key_info)+ table->keys;
|
||||
|
||||
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 */
|
||||
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++)
|
||||
{
|
||||
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)
|
||||
break;
|
||||
}
|
||||
@ -1001,7 +1038,7 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
for (i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
Item_field *field;
|
||||
if ((field= trans[i]->filed_for_view_update()) &&
|
||||
if ((field= trans[i].item->filed_for_view_update()) &&
|
||||
field->field == *field_ptr)
|
||||
break;
|
||||
}
|
||||
@ -1035,24 +1072,33 @@ bool check_key_in_view(THD *thd, TABLE_LIST *view)
|
||||
insert_view_fields()
|
||||
list list for insertion
|
||||
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;
|
||||
Item **trans;
|
||||
Field_translator *trans;
|
||||
DBUG_ENTER("insert_view_fields");
|
||||
|
||||
if (!(trans= view->field_translation))
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
for (uint i= 0; i < elements_in_view; i++)
|
||||
{
|
||||
Item_field *fld;
|
||||
if ((fld= trans[i]->filed_for_view_update()))
|
||||
if ((fld= trans[i].item->filed_for_view_update()))
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -4836,11 +4836,11 @@ when_list2:
|
||||
table_ref:
|
||||
table_factor { $$=$1; }
|
||||
| join_table { $$=$1; }
|
||||
{
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->nest_last_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
join_table_list:
|
||||
@ -4930,20 +4930,20 @@ table_factor:
|
||||
sel->get_use_index(),
|
||||
sel->get_ignore_index())))
|
||||
YYABORT;
|
||||
sel->add_joined_table($$);
|
||||
sel->add_joined_table($$);
|
||||
}
|
||||
| '('
|
||||
{
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (lex->current_select->init_nested_join(lex->thd))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
join_table_list ')'
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
if (!($$= lex->current_select->end_nested_join(lex->thd)))
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
|
||||
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
|
||||
| '(' SELECT_SYM select_derived ')' opt_table_alias
|
||||
|
256
sql/table.cc
256
sql/table.cc
@ -1517,11 +1517,68 @@ void st_table_list::calc_md5(char *buffer)
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
{
|
||||
if (ancestor->ancestor)
|
||||
ancestor->set_ancestor();
|
||||
table= ancestor->table;
|
||||
schema_table= ancestor->schema_table;
|
||||
ancestor->table->grant= grant;
|
||||
/* process all tables of view */
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor)
|
||||
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,
|
||||
uint8 check_opt_type)
|
||||
{
|
||||
Item **transl;
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= &view->select_lex;
|
||||
SELECT_LEX *current_select_save= thd->lex->current_select;
|
||||
Item *item;
|
||||
TABLE_LIST *tbl;
|
||||
List_iterator_fast<Item> it(select->item_list);
|
||||
uint i= 0;
|
||||
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;
|
||||
DBUG_ENTER("st_table_list::setup_ancestor");
|
||||
|
||||
if (ancestor->ancestor &&
|
||||
ancestor->setup_ancestor(thd, conds,
|
||||
(check_opt_type == VIEW_CHECK_CASCADED ?
|
||||
VIEW_CHECK_CASCADED :
|
||||
VIEW_CHECK_NONE)))
|
||||
DBUG_RETURN(1);
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor &&
|
||||
tbl->setup_ancestor(thd, conds,
|
||||
(check_opt_type == VIEW_CHECK_CASCADED ?
|
||||
VIEW_CHECK_CASCADED :
|
||||
VIEW_CHECK_NONE)))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
if (field_translation)
|
||||
{
|
||||
/* prevent look up in SELECTs tree */
|
||||
thd->lex->current_select= &thd->lex->select_lex;
|
||||
thd->lex->select_lex.no_wrap_view_item= 1;
|
||||
thd->set_query_id= 1;
|
||||
/* this view was prepared already on previous PS/SP execution */
|
||||
Item **end= field_translation + select->item_list.elements;
|
||||
for (Item **item= field_translation; item < end; item++)
|
||||
Field_translator *end= field_translation + select->item_list.elements;
|
||||
/* 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 */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* 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 (!transl->item->fixed &&
|
||||
transl->item->fix_fields(thd, ancestor, &transl->item))
|
||||
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;
|
||||
}
|
||||
|
||||
/* view fields translation table */
|
||||
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);
|
||||
}
|
||||
@ -1609,22 +1686,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
|
||||
used fields correctly.
|
||||
*/
|
||||
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++))
|
||||
{
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
/* save original name of view column */
|
||||
char *name= item->name;
|
||||
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
|
||||
goto err;
|
||||
ancestor->table->grant.want_privilege= want_privilege;
|
||||
transl[i++]= item;
|
||||
/* set new item get in fix fields and original column name */
|
||||
transl[i].name= name;
|
||||
transl[i++].item= item;
|
||||
}
|
||||
field_translation= transl;
|
||||
/* 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 ||
|
||||
(check_opt_type == VIEW_CHECK_CASCADED &&
|
||||
ancestor->check_option))
|
||||
@ -1697,6 +1781,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
|
||||
if (arena)
|
||||
thd->restore_backup_item_arena(arena, &backup);
|
||||
}
|
||||
restore_want_privilege();
|
||||
|
||||
/*
|
||||
fix_fields do not need tables, because new are only AND operation and we
|
||||
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))
|
||||
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 */
|
||||
if (view->select_lex.ftfunc_list->elements)
|
||||
{
|
||||
@ -1749,9 +1844,10 @@ void st_table_list::cleanup_items()
|
||||
if (!field_translation)
|
||||
return;
|
||||
|
||||
Item **end= field_translation + view->select_lex.item_list.elements;
|
||||
for (Item **item= field_translation; item < end; item++)
|
||||
(*item)->walk(&Item::cleanup_processor, 0);
|
||||
Field_translator *end= (field_translation +
|
||||
view->select_lex.item_list.elements);
|
||||
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)
|
||||
{
|
||||
ptr= table->field_translation;
|
||||
@ -1810,7 +1996,7 @@ Item *Field_iterator_table::item(THD *thd)
|
||||
|
||||
const char *Field_iterator_view::name()
|
||||
{
|
||||
return (*ptr)->name;
|
||||
return ptr->name;
|
||||
}
|
||||
|
||||
|
||||
|
19
sql/table.h
19
sql/table.h
@ -274,6 +274,11 @@ typedef struct st_schema_table
|
||||
|
||||
struct st_lex;
|
||||
class select_union;
|
||||
struct Field_translator
|
||||
{
|
||||
Item *item;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
typedef struct st_table_list
|
||||
{
|
||||
@ -308,11 +313,13 @@ typedef struct st_table_list
|
||||
/* link to select_lex where this table was used */
|
||||
st_select_lex *select_lex;
|
||||
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) */
|
||||
st_table_list *ancestor;
|
||||
/* most upper view this table belongs to */
|
||||
st_table_list *belong_to_view;
|
||||
/* list of join table tree leaves */
|
||||
st_table_list *next_leaf;
|
||||
Item *where; /* VIEW WHERE clause condition */
|
||||
Item *check_option; /* WITH CHECK OPTION condition */
|
||||
LEX_STRING query; /* text of (CRETE/SELECT) statement */
|
||||
@ -332,6 +339,7 @@ typedef struct st_table_list
|
||||
*/
|
||||
uint8 effective_with_check;
|
||||
uint effective_algorithm; /* which algorithm was really used */
|
||||
uint privilege_backup; /* place for saving privileges */
|
||||
GRANT_INFO grant;
|
||||
thr_lock_type lock_type;
|
||||
uint outer_join; /* Which join type */
|
||||
@ -366,6 +374,11 @@ typedef struct st_table_list
|
||||
void cleanup_items();
|
||||
bool placeholder() {return derived || view; }
|
||||
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;
|
||||
|
||||
class Item;
|
||||
@ -400,14 +413,14 @@ public:
|
||||
|
||||
class Field_iterator_view: public Field_iterator
|
||||
{
|
||||
Item **ptr, **array_end;
|
||||
Field_translator *ptr, *array_end;
|
||||
public:
|
||||
Field_iterator_view() :ptr(0), array_end(0) {}
|
||||
void set(TABLE_LIST *table);
|
||||
void next() { ptr++; }
|
||||
bool end_of_fields() { return ptr == array_end; }
|
||||
const char *name();
|
||||
Item *item(THD *thd) { return *ptr; }
|
||||
Item *item(THD *thd) { return ptr->item; }
|
||||
Field *field() { return 0; }
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user