merge
This commit is contained in:
commit
0ef0b030a5
@ -387,4 +387,7 @@
|
||||
#define ER_VIEW_NONUPD_CHECK 1368
|
||||
#define ER_VIEW_CHECK_FAILED 1369
|
||||
#define ER_SP_ACCESS_DENIED_ERROR 1370
|
||||
#define ER_ERROR_MESSAGES 371
|
||||
#define ER_VIEW_MULTIUPDATE 1371
|
||||
#define ER_VIEW_NO_INSERT_FIELD_LIST 1372
|
||||
#define ER_VIEW_DELETE_MERGE_VIEW 1373
|
||||
#define ER_ERROR_MESSAGES 374
|
||||
|
@ -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;
|
||||
@ -1646,3 +1646,200 @@ insert into v4 values (30);
|
||||
ERROR HY000: You can't specify target table 'v4' for update in FROM clause
|
||||
drop view v4, v3, v2, v1;
|
||||
drop table t1;
|
||||
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);
|
||||
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;
|
||||
|
@ -1588,3 +1588,120 @@ create view v4 as select * from v2 where 20 < (select (s1) from t1);
|
||||
insert into v4 values (30);
|
||||
drop view v4, v3, v2, v1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# 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;
|
||||
|
35
sql/item.cc
35
sql/item.cc
@ -45,12 +45,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 */
|
||||
@ -80,6 +79,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),
|
||||
@ -110,10 +110,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;
|
||||
}
|
||||
|
||||
@ -134,6 +136,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),
|
||||
@ -2648,6 +2670,11 @@ void Item_ref::cleanup()
|
||||
DBUG_ENTER("Item_ref::cleanup");
|
||||
Item_ident::cleanup();
|
||||
result_field= 0;
|
||||
DBUG_PRINT("info", ("hook: 0x%lx(0x%lx) original item: 0x%lx",
|
||||
(ulong)hook_ptr, (ulong)(hook_ptr?*hook_ptr:0),
|
||||
(ulong)orig_item));
|
||||
if (hook_ptr)
|
||||
*hook_ptr= orig_item;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,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 */
|
||||
@ -164,6 +166,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -619,7 +619,8 @@ int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> *fields, List<Item> *values,
|
||||
COND *conds, ulong options,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
|
||||
bool converted);
|
||||
int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
List<Item> &fields, List_item *values,
|
||||
List<Item> &update_fields,
|
||||
@ -783,13 +784,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);
|
||||
int 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,7 +59,7 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
|
||||
|
||||
SYNOPSIS
|
||||
opt_sum_query()
|
||||
tables Tables in query
|
||||
tables list of leaves of join table tree
|
||||
all_fields All fields to be returned
|
||||
conds WHERE clause
|
||||
|
||||
@ -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))
|
||||
|
@ -399,3 +399,6 @@ character-set=latin2
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -390,3 +390,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -399,3 +399,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -392,3 +392,6 @@ character-set=latin7
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -400,3 +400,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=greek
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -392,3 +392,6 @@ character-set=latin2
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -391,3 +391,6 @@ character-set=ujis
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=euckr
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -389,3 +389,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -389,3 +389,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -392,3 +392,6 @@ character-set=latin2
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -389,3 +389,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -392,3 +392,6 @@ character-set=latin2
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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 ÓÏÄÅÒÖÉÔ ÓÓÙÌËÕ ÎÁ ×ÒÅÍÅÎÎÕÀ ÔÁÂÌÉÃÕ '%-.64s'"
|
||||
"View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
|
||||
"áÌÇÏÒÉÔÍ ÓÌÉÑÎÉÑ view ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ÓÅÊÞÁÓ (ÁÌÇÏÒÉÔÍ ÂÕÄÅÔ ÎÅÏÐÅÒÅÄÅÌÅÎÎÙÍ)"
|
||||
"Обновляемый view не содержит ключа использованной в нем таблиц(ы)"
|
||||
"Обновляемый view не содержит ключа использованных(ой) в нем таблиц(ы)"
|
||||
"View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ"
|
||||
"Can't drop a %s from within another stored routine"
|
||||
"GOTO is not allowed in a stored procedure handler"
|
||||
@ -392,3 +392,6 @@ character-set=koi8r
|
||||
"CHECK OPTION ÄÌÑ ÎÅÏÂÎÏ×ÌÑÅÍÏÇÏ VIEW '%-.64s.%-.64s'"
|
||||
"ÐÒÏ×ÅÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÐÒÏ×ÁÌÉÌÁÓØ"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"Нельзя изменить больше чем одну базовую таблицу используя многотабличный VIEW '%-.64s.%-.64s'"
|
||||
"Нельзя вставлять записи в многотабличный VIEW '%-.64s.%-.64s' без списка полей"
|
||||
"Нельзя удалять из многотабличного VIEW '%-.64s.%-.64s'"
|
||||
|
@ -380,3 +380,6 @@ character-set=cp1250
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -395,3 +395,6 @@ character-set=latin2
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -391,3 +391,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -387,3 +387,6 @@ character-set=latin1
|
||||
"CHECK OPTION on non-updatable view '%-.64s.%-.64s'"
|
||||
"CHECK OPTION failed '%-.64s.%-.64s'"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"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'"
|
||||
|
@ -393,3 +393,6 @@ character-set=koi8u
|
||||
"CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÝÏ ÎÅ ÍÏÖÅ ÂÕÔÉ ÏÎÏ×ÌÅÎÎÉÍ"
|
||||
"ÐÅÒÅצÒËÁ CHECK OPTION ÄÌÑ VIEW '%-.64s.%-.64s' ÎÅ ÐÒÏÊÛÌÁ"
|
||||
"Access denied; you are not the procedure/function definer of '%s'"
|
||||
"Неможливо оновити б╕льш ниж одну базову таблицю выкористовуючи VIEW '%-.64s.%-.64s', що м╕ст╕ть дек╕лька таблиць"
|
||||
"Неможливо уставити рядки у VIEW '%-.64s.%-.64s', що м╕стить дек╕лька таблиць, без списку стовбц╕в"
|
||||
"Неможливо видалити рядки у VIEW '%-.64s.%-.64s', що м╕стить дек╕лька таблиць"
|
||||
|
@ -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++)
|
||||
|
179
sql/sql_base.cc
179
sql/sql_base.cc
@ -579,14 +579,14 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!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)))
|
||||
table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -594,12 +594,12 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
|
||||
{
|
||||
for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
|
||||
{
|
||||
if ((!strcmp(table->db, db_name) &&
|
||||
if (table->table->tmp_table == NO_TMP_TABLE &&
|
||||
((!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
|
||||
(table->view &&
|
||||
!strcmp(table->table->table_cache_key, db_name) &&
|
||||
!strcmp(table->table->table_name, table_name)))
|
||||
!strcmp(table->table->table_name, table_name))))
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2084,15 +2084,18 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
bool allow_rowid,
|
||||
uint *cached_field_index_ptr)
|
||||
{
|
||||
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 &&
|
||||
@ -2100,13 +2103,13 @@ 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)
|
||||
@ -2115,10 +2118,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
|
||||
(*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,
|
||||
@ -2132,10 +2135,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);
|
||||
}
|
||||
|
||||
|
||||
@ -2264,6 +2267,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
field makes some prepared query ambiguous and so erronous, but we
|
||||
accept this trade off.
|
||||
*/
|
||||
if (item->cached_table->table)
|
||||
{
|
||||
found= find_field_in_real_table(thd, item->cached_table->table,
|
||||
name, length,
|
||||
test(item->cached_table->
|
||||
@ -2271,6 +2276,20 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
|
||||
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));
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
if (found == WRONG_GRANT)
|
||||
@ -2302,7 +2321,8 @@ 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) &&
|
||||
@ -2356,7 +2376,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)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||
@ -2366,7 +2386,8 @@ 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) &&
|
||||
@ -2696,7 +2717,6 @@ int 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(-1); /* purecov: inspected */
|
||||
}
|
||||
if (ref)
|
||||
@ -2710,6 +2730,36 @@ int 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
|
||||
|
||||
@ -2718,11 +2768,14 @@ int 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.
|
||||
@ -2732,16 +2785,23 @@ int 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);
|
||||
@ -2763,16 +2823,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);
|
||||
}
|
||||
|
||||
@ -2875,9 +2943,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)
|
||||
{
|
||||
@ -2890,6 +2961,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
else
|
||||
{
|
||||
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,
|
||||
@ -2898,8 +2970,17 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
natural_join_table= 0;
|
||||
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;
|
||||
last= embedded= tables;
|
||||
|
||||
while ((embedding= embedded->embedding) &&
|
||||
@ -2926,9 +3007,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())
|
||||
@ -2948,6 +3035,11 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
(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(), NULL, tables->view_name.str,
|
||||
field_name);
|
||||
}
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (any_privileges)
|
||||
{
|
||||
@ -3013,7 +3105,11 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
|
||||
thd->mem_root);
|
||||
}
|
||||
}
|
||||
/* All fields are used */
|
||||
/*
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -3031,10 +3127,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;
|
||||
@ -3059,7 +3161,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
}
|
||||
|
||||
/* Check if we are using outer joins */
|
||||
for (TABLE_LIST *table= tables; table; table= table->next_local)
|
||||
for (TABLE_LIST *table= leaves; table; table= table->next_leaf)
|
||||
{
|
||||
TABLE_LIST *embedded;
|
||||
TABLE_LIST *embedding= table;
|
||||
@ -3123,8 +3225,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;
|
||||
@ -3160,6 +3262,13 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
t2_field->query_id= thd->query_id;
|
||||
t2->used_keys.intersect(t2_field->part_of_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(t2_field == view_ref_found &&
|
||||
item_t2->type() == Item::REF_ITEM);
|
||||
/* remove hooking to stack variable */
|
||||
((Item_ref*) item_t2)->hook_ptr= 0;
|
||||
}
|
||||
if ((t1_field= iterator->field()))
|
||||
{
|
||||
/* Mark field used for table cache */
|
||||
|
@ -1642,7 +1642,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;
|
||||
@ -1655,8 +1657,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);
|
||||
|
@ -43,7 +43,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
|
||||
|
||||
if ((error= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(error);
|
||||
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;
|
||||
@ -284,8 +291,8 @@ int 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(-1);
|
||||
if (!table_list->updatable || check_key_in_view(thd, table_list))
|
||||
@ -341,7 +348,8 @@ int 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(-1);
|
||||
|
||||
/* Fix tables-to-be-deleted-from list to point at opened tables */
|
||||
|
@ -619,6 +619,7 @@ int 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";
|
||||
@ -647,7 +648,7 @@ int 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)))
|
||||
{
|
||||
|
@ -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_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||
@ -97,6 +113,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)
|
||||
{
|
||||
@ -111,6 +144,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;
|
||||
}
|
||||
|
||||
@ -135,7 +177,7 @@ int 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
|
||||
@ -202,17 +244,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
if (res || thd->is_fatal_error)
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -220,6 +259,9 @@ int 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++))
|
||||
@ -466,7 +508,7 @@ int 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(0);
|
||||
|
||||
@ -476,7 +518,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(-1);
|
||||
}
|
||||
@ -507,8 +549,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");
|
||||
@ -521,19 +564,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;
|
||||
@ -552,7 +599,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
|
||||
}
|
||||
}
|
||||
@ -573,32 +620,34 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 ERROR
|
||||
1 ERROR and message sent to client
|
||||
-1 ERROR but message is not sent to client
|
||||
*/
|
||||
|
||||
static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
|
||||
List<Item> &fields, COND **where)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -627,8 +676,9 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
|
||||
int 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) ||
|
||||
@ -1650,22 +1700,48 @@ bool delayed_insert::handle_inserts(void)
|
||||
|
||||
RETURN
|
||||
0 OK
|
||||
-1 Error
|
||||
1 Error sent to client
|
||||
-1 Error is not sent to client
|
||||
*/
|
||||
|
||||
int 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
|
||||
clasue if table is VIEW
|
||||
*/
|
||||
lex->query_tables->no_where_clause= 1;
|
||||
if (mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
if ((res= mysql_prepare_insert_check_table(thd, lex->query_tables,
|
||||
lex->field_list,
|
||||
&lex->select_lex.where))
|
||||
DBUG_RETURN(-1);
|
||||
&lex->select_lex.where)))
|
||||
DBUG_RETURN(res);
|
||||
/*
|
||||
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(0);
|
||||
}
|
||||
|
||||
@ -1694,6 +1770,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_independent()))
|
||||
{
|
||||
/* 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;
|
||||
|
@ -1041,7 +1041,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;
|
||||
@ -1635,7 +1635,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;
|
||||
|
@ -143,7 +143,8 @@ int 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(-1);
|
||||
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,
|
||||
|
@ -2797,18 +2797,29 @@ unsent_create_error:
|
||||
lex->duplicates);
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
if (res != 2)
|
||||
break;
|
||||
case SQLCOM_UPDATE_MULTI:
|
||||
{
|
||||
bool converted= 0;
|
||||
DBUG_ASSERT(first_table == all_tables && first_table != 0);
|
||||
if (res != 2)
|
||||
{
|
||||
if ((res= multi_update_precheck(thd, all_tables)))
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
res= 0;
|
||||
converted= 1;
|
||||
}
|
||||
res= mysql_multi_update(thd, all_tables,
|
||||
&select_lex->item_list,
|
||||
&lex->value_list,
|
||||
select_lex->where,
|
||||
select_lex->options,
|
||||
lex->duplicates, unit, select_lex);
|
||||
lex->duplicates, unit, select_lex,
|
||||
converted);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REPLACE:
|
||||
@ -2846,35 +2857,28 @@ unsent_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,
|
||||
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;
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
}
|
||||
@ -2935,8 +2939,20 @@ unsent_create_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)))
|
||||
break;
|
||||
|
||||
if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
|
||||
|
@ -959,6 +959,7 @@ error:
|
||||
|
||||
RETURN VALUE
|
||||
0 success
|
||||
2 convert to multi_update
|
||||
1 error, sent to client
|
||||
-1 error, not sent to client
|
||||
*/
|
||||
@ -975,6 +976,15 @@ static int mysql_test_update(Prepared_statement *stmt,
|
||||
|
||||
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,
|
||||
@ -1027,6 +1037,15 @@ static int mysql_test_delete(Prepared_statement *stmt,
|
||||
|
||||
if (!(res=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);
|
||||
}
|
||||
|
||||
res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
|
||||
lex->unit.cleanup();
|
||||
}
|
||||
@ -1233,7 +1252,10 @@ static int select_like_statement_test(Prepared_statement *stmt,
|
||||
LEX *lex= stmt->lex;
|
||||
int 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)))
|
||||
@ -1299,6 +1321,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
|
||||
0 success
|
||||
@ -1306,10 +1329,11 @@ static int mysql_test_create_table(Prepared_statement *stmt)
|
||||
-1 error, not sent to client
|
||||
*/
|
||||
static int mysql_test_multiupdate(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables)
|
||||
TABLE_LIST *tables,
|
||||
bool converted)
|
||||
{
|
||||
int res;
|
||||
if ((res= multi_update_precheck(stmt->thd, tables)))
|
||||
if (!converted && (res= multi_update_precheck(stmt->thd, tables)))
|
||||
return res;
|
||||
/*
|
||||
here we do not pass tables for opening, tables will be opened and locked
|
||||
@ -1343,7 +1367,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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1434,6 +1470,11 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
|
||||
|
||||
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:
|
||||
@ -1462,10 +1503,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
|
||||
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:
|
||||
res= mysql_test_insert_select(stmt, tables);
|
||||
@ -1763,8 +1800,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,
|
||||
@ -247,6 +247,7 @@ int 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,
|
||||
@ -259,7 +260,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,
|
||||
@ -306,12 +307,13 @@ 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,
|
||||
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 */
|
||||
@ -379,7 +381,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++;
|
||||
}
|
||||
{
|
||||
@ -580,7 +584,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)
|
||||
{
|
||||
@ -606,11 +610,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"));
|
||||
@ -1072,7 +1076,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);
|
||||
}
|
||||
|
||||
@ -1177,7 +1181,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,
|
||||
@ -2078,7 +2082,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;
|
||||
@ -2108,7 +2112,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;
|
||||
@ -5065,6 +5069,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;
|
||||
@ -5108,6 +5113,7 @@ make_outerjoin_info(JOIN *join)
|
||||
nested_join->first_nested->last_inner= tab;
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -5210,7 +5216,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));
|
||||
}
|
||||
|
||||
}
|
||||
@ -5399,13 +5407,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();
|
||||
@ -5957,7 +5970,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;
|
||||
@ -8799,6 +8812,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())
|
||||
{
|
||||
/*
|
||||
@ -11510,7 +11524,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,6 +86,28 @@ static bool check_fields(THD *thd, List<Item> &items)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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 and error sent to client
|
||||
-1 - error and error is not sent to client
|
||||
*/
|
||||
|
||||
int mysql_update(THD *thd,
|
||||
TABLE_LIST *table_list,
|
||||
List<Item> &fields,
|
||||
@ -118,6 +140,15 @@ int mysql_update(THD *thd,
|
||||
|
||||
if ((error= open_and_lock_tables(thd, table_list)))
|
||||
DBUG_RETURN(error);
|
||||
|
||||
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"));
|
||||
/* convert to multiupdate */
|
||||
return 2;
|
||||
}
|
||||
thd->proc_info="init";
|
||||
table= table_list->table;
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
@ -520,8 +551,8 @@ int 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) ||
|
||||
@ -579,6 +610,7 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
TABLE_LIST *table_list= lex->query_tables;
|
||||
List<Item> *fields= &lex->select_lex.item_list;
|
||||
TABLE_LIST *tl;
|
||||
TABLE_LIST *leaves;
|
||||
table_map tables_for_update;
|
||||
int res;
|
||||
bool update_view= 0;
|
||||
@ -590,21 +622,25 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
if (open_tables(thd, table_list, & table_count) ||
|
||||
mysql_handle_derived(lex, &mysql_derived_prepare))
|
||||
DBUG_RETURN(thd->net.report_error ? -1 : 1);
|
||||
if (setup_tables(thd, table_list, &lex->select_lex.where,
|
||||
&lex->select_lex.leaf_tables, 0))
|
||||
DBUG_RETURN(-1);
|
||||
/*
|
||||
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);
|
||||
}
|
||||
|
||||
@ -613,8 +649,7 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
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))
|
||||
@ -639,16 +674,8 @@ int mysql_multi_update_prepare(THD *thd)
|
||||
/*
|
||||
Setup timestamp handling and locking mode
|
||||
*/
|
||||
for (tl= table_list; tl ; tl= tl->next_local)
|
||||
{
|
||||
TABLE *table= tl->table;
|
||||
for (tl= leaves; tl; tl= tl->next_leaf)
|
||||
|
||||
/* We only need SELECT privilege for columns in the values list */
|
||||
tl->grant.want_privilege= table->grant.want_privilege=
|
||||
(SELECT_ACL & ~table->grant.privilege);
|
||||
// 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;
|
||||
|
||||
/* if table will be updated then check that it is unique */
|
||||
@ -738,16 +765,19 @@ int mysql_multi_update(THD *thd,
|
||||
COND *conds,
|
||||
ulong options,
|
||||
enum enum_duplicates handle_duplicates,
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
|
||||
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
|
||||
bool converted)
|
||||
{
|
||||
int res;
|
||||
int res= 0;
|
||||
multi_update *result;
|
||||
DBUG_ENTER("mysql_multi_update");
|
||||
|
||||
if ((res= mysql_multi_update_prepare(thd)))
|
||||
DBUG_RETURN(res);
|
||||
|
||||
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(-1);
|
||||
|
||||
@ -771,12 +801,14 @@ int 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)
|
||||
{}
|
||||
|
||||
|
||||
@ -823,8 +855,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)
|
||||
{
|
||||
@ -891,7 +924,7 @@ 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) &&
|
||||
|
@ -499,9 +499,17 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
|
||||
view->updatable_view= 0;
|
||||
break;
|
||||
}
|
||||
for (TABLE_LIST *up= tbl; up; up= up->embedding)
|
||||
{
|
||||
if (up->outer_join)
|
||||
{
|
||||
view->updatable_view= 0;
|
||||
goto loop_out;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
loop_out:
|
||||
/*
|
||||
Check that table of main select do not used in subqueries.
|
||||
|
||||
@ -567,6 +575,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;
|
||||
|
||||
/*
|
||||
@ -609,7 +618,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;
|
||||
@ -652,6 +662,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)
|
||||
{
|
||||
@ -710,7 +721,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;
|
||||
|
||||
/*
|
||||
@ -747,9 +758,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);
|
||||
|
||||
@ -759,20 +767,48 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
|
||||
table->effective_with_check= 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;
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
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)?
|
||||
*/
|
||||
view_tables->lock_type= table->lock_type;
|
||||
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.
|
||||
@ -799,13 +835,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;
|
||||
}
|
||||
@ -816,7 +852,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;
|
||||
@ -953,24 +989,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++)
|
||||
@ -987,7 +1025,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;
|
||||
}
|
||||
@ -1008,7 +1046,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;
|
||||
}
|
||||
@ -1042,22 +1080,31 @@ 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 @@ int 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);
|
||||
|
||||
|
226
sql/table.cc
226
sql/table.cc
@ -1517,10 +1517,65 @@ void st_table_list::calc_md5(char *buffer)
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
{
|
||||
if (ancestor->ancestor)
|
||||
/* 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;
|
||||
ancestor->table->grant= grant;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1550,10 +1605,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;
|
||||
@ -1561,38 +1617,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,
|
||||
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++)
|
||||
{
|
||||
/* TODO: fix for several tables in VIEW */
|
||||
uint want_privilege= ancestor->table->grant.want_privilege;
|
||||
Field_translator *end= field_translation + select->item_list.elements;
|
||||
/* real rights will be checked in VIEW field */
|
||||
ancestor->table->grant.want_privilege= 0;
|
||||
save_and_clear_want_privilege();
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
|
||||
for (transl= field_translation; transl < end; transl++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -1608,22 +1683,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
|
||||
used fields correctly.
|
||||
*/
|
||||
thd->set_query_id= 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;
|
||||
save_and_clear_want_privilege();
|
||||
/* aggregate function are allowed */
|
||||
thd->allow_sum_func= 1;
|
||||
while ((item= it++))
|
||||
{
|
||||
/* 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))
|
||||
@ -1696,6 +1778,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
|
||||
@ -1704,6 +1788,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)
|
||||
{
|
||||
@ -1788,6 +1881,95 @@ 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 sbelong 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
|
||||
0 table not found or found only one
|
||||
1 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 1;
|
||||
else
|
||||
*table= tbl;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (tbl->check_single_table(table, map))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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;
|
||||
@ -1809,7 +1991,7 @@ Item *Field_iterator_table::item(THD *thd)
|
||||
|
||||
const char *Field_iterator_view::name()
|
||||
{
|
||||
return (*ptr)->name;
|
||||
return ptr->name;
|
||||
}
|
||||
|
||||
|
||||
|
20
sql/table.h
20
sql/table.h
@ -224,6 +224,12 @@ struct st_table {
|
||||
struct st_lex;
|
||||
struct select_union;
|
||||
|
||||
struct Field_translator
|
||||
{
|
||||
Item *item;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
typedef struct st_table_list
|
||||
{
|
||||
/* link in a local table list (used by SQL_LIST) */
|
||||
@ -255,11 +261,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 */
|
||||
@ -279,6 +287,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 */
|
||||
@ -313,6 +322,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;
|
||||
@ -347,14 +361,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; }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user