summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2004-11-11 21:18:10 +0200
committerunknown <bell@sanja.is.com.ua>2004-11-11 21:18:10 +0200
commit3bc1fcd409eb08474884a556fef193d707117212 (patch)
treeb838d2bae358ea54b828bff0e3dfb8a0faf1bc8e
parente5fd013fdf6c8664daa0bbdcaf0d22bf44e90d62 (diff)
parent5b82bc6644fb766c7a04b49d60e70c474450ce28 (diff)
downloadmariadb-git-3bc1fcd409eb08474884a556fef193d707117212.tar.gz
merge
sql/item_cmpfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/mysql_priv.h: Auto merged sql/opt_sum.cc: Auto merged sql/sp.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_delete.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_load.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_view.h: Auto merged sql/sql_yacc.yy: Auto merged
-rw-r--r--include/mysqld_error.h5
-rw-r--r--mysql-test/r/view.result199
-rw-r--r--mysql-test/t/view.test117
-rw-r--r--sql/item.cc35
-rw-r--r--sql/item.h3
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/item_subselect.cc7
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/opt_sum.cc10
-rw-r--r--sql/share/czech/errmsg.txt3
-rw-r--r--sql/share/danish/errmsg.txt3
-rw-r--r--sql/share/dutch/errmsg.txt3
-rw-r--r--sql/share/english/errmsg.txt3
-rw-r--r--sql/share/estonian/errmsg.txt3
-rw-r--r--sql/share/french/errmsg.txt3
-rw-r--r--sql/share/german/errmsg.txt3
-rw-r--r--sql/share/greek/errmsg.txt3
-rw-r--r--sql/share/hungarian/errmsg.txt3
-rw-r--r--sql/share/italian/errmsg.txt3
-rw-r--r--sql/share/japanese/errmsg.txt3
-rw-r--r--sql/share/korean/errmsg.txt3
-rw-r--r--sql/share/norwegian-ny/errmsg.txt3
-rw-r--r--sql/share/norwegian/errmsg.txt3
-rw-r--r--sql/share/polish/errmsg.txt3
-rw-r--r--sql/share/portuguese/errmsg.txt3
-rw-r--r--sql/share/romanian/errmsg.txt3
-rw-r--r--sql/share/russian/errmsg.txt5
-rw-r--r--sql/share/serbian/errmsg.txt3
-rw-r--r--sql/share/slovak/errmsg.txt3
-rw-r--r--sql/share/spanish/errmsg.txt3
-rw-r--r--sql/share/swedish/errmsg.txt3
-rw-r--r--sql/share/ukrainian/errmsg.txt3
-rw-r--r--sql/sp.cc3
-rw-r--r--sql/sql_base.cc215
-rw-r--r--sql/sql_class.h9
-rw-r--r--sql/sql_delete.cc16
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_insert.cc163
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_load.cc3
-rw-r--r--sql/sql_olap.cc2
-rw-r--r--sql/sql_parse.cc64
-rw-r--r--sql/sql_prepare.cc60
-rw-r--r--sql/sql_select.cc44
-rw-r--r--sql/sql_update.cc87
-rw-r--r--sql/sql_view.cc111
-rw-r--r--sql/sql_view.h2
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.cc244
-rw-r--r--sql/table.h20
51 files changed, 1256 insertions, 268 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 1e190496fde..8270dd6ee73 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -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
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 18fa7c2e374..4d21d30a90c 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -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;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 27b127a0093..d002522137c 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -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;
diff --git a/sql/item.cc b/sql/item.cc
index 9e28793493d..41203e3365c 100644
--- a/sql/item.cc
+++ b/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;
}
diff --git a/sql/item.h b/sql/item.h
index 93c396b95b0..66a6827f4a9 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -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);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index af2c385b296..14d240fe91d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -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);
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f426f14a25f..16a08dca009 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -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);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index b343beaa4e4..8dfc976071d 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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);
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 30033bc39eb..44df305cb35 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -59,9 +59,9 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
SYNOPSIS
opt_sum_query()
- tables Tables in query
- all_fields All fields to be returned
- conds WHERE clause
+ tables list of leaves of join table tree
+ all_fields All fields to be returned
+ conds WHERE clause
NOTE:
This function is only called for queries with sum functions and no
@@ -89,7 +89,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
where_tables= conds->used_tables();
/* Don't replace expression on a table that is part of an outer join */
- for (TABLE_LIST *tl= tables; tl; tl= tl->next_local)
+ for (TABLE_LIST *tl= tables; tl; tl= tl->next_leaf)
{
if (tl->on_expr)
{
@@ -128,7 +128,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
{
longlong count= 1;
TABLE_LIST *table;
- for (table= tables; table; table= table->next_local)
+ for (table= tables; table; table= table->next_leaf)
{
if (outer_tables || (table->table->file->table_flags() &
HA_NOT_EXACT_COUNT))
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index e3c08eeca89..ad2018d98cb 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -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'"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 78610219ade..4f2d55fd87f 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -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'"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 051a2a13ab8..ff86410cd6c 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -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'"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index bb2a9cb59ba..e931a866bd3 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -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'"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 14764d764aa..5ca22eeeaa7 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -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'"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 7c3e833c903..ba0af3bd5f8 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -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'"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 7cda8bef089..a34d01ea33e 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -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'"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 7b9bf7e967e..aa0cb0b658a 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -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'"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index d4e5c5c744f..6c67b59fafd 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -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'"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index c697edb4cd7..3373e6f9932 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -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'"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index e1a32f1894b..c0bb8a2a9f3 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -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'"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index adb08b67474..57022772eae 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -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'"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 057accd3c5b..c0588ceddfe 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -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'"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 5506d95592a..880c8a74289 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -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'"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 38cefd45338..e7b0484561a 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -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'"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 7689db06451..2434fc13d5b 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -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'"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index ad486367ec9..02429246e9d 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -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'"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index d057ab53256..8c8de62bfb2 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -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'"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 6e38b1c3d11..6852139dee6 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -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'"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index a9667b8ba62..bc31604e02d 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -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'"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 17600f336c0..60483585614 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -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'"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 8b061ac0eec..b8b6ca3d1f8 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -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'"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 317b2d596fa..c07a0bf7cfb 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -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', ÝÏ Í¦ÓÔÉÔØ ÄÅ˦ÌØËÁ ÔÁÂÌÉÃØ"
diff --git a/sql/sp.cc b/sql/sp.cc
index 96bb8a17a49..3236b3640a6 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -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++)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1cee6d2c3a6..5146a140479 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -556,10 +556,10 @@ void close_temporary_tables(THD *thd)
SYNOPSIS
find_table_in_list()
- table Pointer to table list
+ table Pointer to table list
offset Offset to which list in table structure to use
- db_name Data base name
- table_name Table name
+ db_name Data base name
+ table_name Table name
NOTES:
This is called by find_table_in_local_list() and
@@ -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) &&
- !strcmp(table->real_name, table_name)) ||
- (table->view &&
- table->table->table_cache_key && // it is not temporary table
- !my_strcasecmp(table_alias_charset,
- table->table->table_cache_key, db_name) &&
- !my_strcasecmp(table_alias_charset,
- table->table->table_name, table_name)))
+ if (table->table->tmp_table == NO_TMP_TABLE &&
+ ((!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name)) ||
+ (table->view &&
+ !my_strcasecmp(table_alias_charset,
+ table->table->table_cache_key, db_name) &&
+ !my_strcasecmp(table_alias_charset,
+ table->table->table_name, table_name))))
break;
}
}
@@ -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) &&
- !strcmp(table->real_name, table_name)) ||
- (table->view && // it is VIEW and
- table->table->table_cache_key && // it is not temporary table
- !strcmp(table->table->table_cache_key, db_name) &&
- !strcmp(table->table->table_name, table_name)))
+ if (table->table->tmp_table == NO_TMP_TABLE &&
+ ((!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name)) ||
+ (table->view &&
+ !strcmp(table->table->table_cache_key, db_name) &&
+ !strcmp(table->table->table_name, table_name))))
break;
}
}
@@ -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,17 +2267,33 @@ 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.
*/
- found= find_field_in_real_table(thd, item->cached_table->table,
- name, length,
- test(item->cached_table->
- table->grant.want_privilege) &&
- check_privileges,
- 1, &(item->cached_field_index));
+ if (item->cached_table->table)
+ {
+ found= find_field_in_real_table(thd, item->cached_table->table,
+ name, length,
+ test(item->cached_table->
+ table->grant.want_privilege) &&
+ check_privileges,
+ 1, &(item->cached_field_index));
+ }
+ else
+ {
+ TABLE_LIST *table= item->cached_table;
+ Field *find= find_field_in_table(thd, table, name, item->name, length,
+ ref,
+ (table->table &&
+ test(table->table->grant.
+ want_privilege) &&
+ check_privileges),
+ (test(table->grant.want_privilege) &&
+ check_privileges),
+ 1, &(item->cached_field_index));
+ }
if (found)
{
if (found == WRONG_GRANT)
- return (Field*) 0;
+ return (Field*) 0;
return found;
}
}
@@ -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)
@@ -2711,6 +2731,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
SYNOPSIS
@@ -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
+ if (table)
+ thd->used_tables|= table->map;
+ else
+ {
+ view_iter.set(tables);
+ for (; !view_iter.end_of_fields(); view_iter.next())
+ {
+ thd->used_tables|= view_iter.item(thd)->used_tables();
+ }
+ }
natural_join_table= 0;
- thd->used_tables|= table->map;
last= embedded= tables;
while ((embedding= embedded->embedding) &&
@@ -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,8 +3105,12 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
thd->mem_root);
}
}
- /* All fields are used */
- table->used_fields=table->fields;
+ /*
+ All fields are used in case if usual tables (in case of view used
+ fields merked in setu_tables during fix_fields of view columns
+ */
+ if (table)
+ table->used_fields=table->fields;
}
}
if (found)
@@ -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 */
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f820f8b9cb9..8faed4110fc 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -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);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 8bdf19195f3..ad792f69a49 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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 */
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index b3d7bebe96a..2cab3f2d3c5 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -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)))
{
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 6e0260d1acb..dfd9fd45b70 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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
}
}
@@ -572,33 +619,35 @@ static bool check_view_insertability(TABLE_LIST *view, ulong query_id)
where Pointer to where clause
RETURN
- 0 ok
- 1 ERROR
+ 0 ok
+ 1 ERROR and message sent to client
+ -1 ERROR but message is not sent to client
*/
-static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
+static int mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
List<Item> &fields, COND **where)
{
bool insert_into_view= (table_list->view != 0);
DBUG_ENTER("mysql_prepare_insert_check_table");
- if (setup_tables(thd, table_list, where))
- DBUG_RETURN(1);
+ if (setup_tables(thd, table_list, where, &thd->lex->select_lex.leaf_tables,
+ 0))
+ DBUG_RETURN(thd->net.report_error ? -1 : 1);
if (insert_into_view && !fields.elements)
{
thd->lex->empty_field_list_on_rset= 1;
- insert_view_fields(&fields, table_list);
+ if (!table_list->table)
+ {
+ DBUG_ASSERT(table_list->view &&
+ table_list->ancestor && table_list->ancestor->next_local);
+ my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0),
+ table_list->view_db.str, table_list->view_name.str);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(insert_view_fields(&fields, table_list));
}
- if (!table_list->updatable ||
- check_key_in_view(thd, table_list) ||
- (insert_into_view &&
- check_view_insertability(table_list, thd->query_id)))
- {
- my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "INSERT");
- DBUG_RETURN(1);
- }
DBUG_RETURN(0);
}
@@ -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,
- lex->field_list,
- &lex->select_lex.where))
- DBUG_RETURN(-1);
+ if ((res= mysql_prepare_insert_check_table(thd, lex->query_tables,
+ lex->field_list,
+ &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;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 86219abc632..97c5058cd61 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -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);
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index c8b4faa47c2..7d72d8ec5e1 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -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;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 9c2a025e089..40529103f00 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -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)
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 20fd7fe2ee0..c287b9e71e7 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -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,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index a14a3da8391..891ff5b8c7e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2797,18 +2797,29 @@ unsent_create_error:
lex->duplicates);
if (thd->net.report_error)
res= -1;
- break;
+ if (res != 2)
+ break;
case SQLCOM_UPDATE_MULTI:
{
+ bool converted= 0;
DBUG_ASSERT(first_table == all_tables && first_table != 0);
- if ((res= multi_update_precheck(thd, all_tables)))
- break;
+ if (res != 2)
+ {
+ if ((res= multi_update_precheck(thd, all_tables)))
+ break;
+ }
+ else
+ {
+ res= 0;
+ 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,
- lex->duplicates == DUP_IGNORE)))
+ res= mysql_insert_select_prepare(thd);
+ if (!res && (result= new select_insert(first_table, first_table->table,
+ &lex->field_list,
+ lex->duplicates,
+ lex->duplicates == DUP_IGNORE)))
{
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_table->next_local;
+ TABLE_LIST *first_select_table;
+
/*
insert/replace from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
*/
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
res= handle_select(thd, lex, result);
- /* revert changes for SP */
- lex->select_lex.table_list.first= (byte*) first_table;
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
}
+ /* revert changes for SP */
+ lex->select_lex.table_list.first= (byte*) first_table;
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,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 1c23162b212..55b03f60b8b 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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:
@@ -1461,10 +1502,6 @@ static int send_prepare_results(Prepared_statement *stmt, bool text_protocol)
case SQLCOM_DELETE_MULTI:
res= mysql_test_multidelete(stmt, tables);
break;
-
- case SQLCOM_UPDATE_MULTI:
- res= mysql_test_multiupdate(stmt, tables);
- break;
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT:
@@ -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();
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 93b46ec874d..37dee433576 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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,13 +307,14 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
- if (setup_tables(thd, tables_list, &conds) ||
+ if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables, 0) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
&all_fields, 1) ||
- setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
- all_fields, &conds, order, group_list,
+ setup_without_group(thd, (*rref_pointer_array), tables_list,
+ select_lex->leaf_tables, fields_list,
+ all_fields, &conds, order, group_list,
&hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
@@ -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));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 561480bd289..b60c0d95658 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -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> &not_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,10 +924,10 @@ int multi_update::prepare(List<Item> &not_used_values,
which will cause an error when reading a row.
(This issue is mostly relevent for MyISAM tables)
*/
- for (table_ref= all_tables; table_ref; table_ref= table_ref->next_local)
+ for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
{
TABLE *table=table_ref->table;
- if (!(tables_to_update & table->map) &&
+ if (!(tables_to_update & table->map) &&
find_table_in_local_list(update_tables, table_ref->db,
table_ref->real_name))
table->no_cache= 1; // Disable row cache
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 760ada9cdbd..d64eada02e9 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -491,17 +491,25 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
{
/* TODO: change here when we will support UNIONs */
for (TABLE_LIST *tbl= (TABLE_LIST *)lex->select_lex.table_list.first;
- tbl;
- tbl= tbl->next_local)
+ tbl;
+ tbl= tbl->next_local)
{
if (tbl->view && !tbl->updatable_view)
{
- view->updatable_view= 0;
- break;
+ 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;
+
/*
- move lock type (TODO: should we issue error in case of TMPTABLE
- algorithm and non-read locking)?
+ Process upper level tables of view. As far as we do noy suport union
+ here we can go through local tables of view most upper SELECT
*/
- view_tables->lock_type= table->lock_type;
+ for(tbl= (TABLE_LIST*)view_select->table_list.first;
+ tbl;
+ tbl= tbl->next_local)
+ {
+ /*
+ move lock type (TODO: should we issue error in case of TMPTABLE
+ algorithm and non-read locking)?
+ */
+ tbl->lock_type= table->lock_type;
+ }
+
+ /* multi table view */
+ if (view_tables->next_local)
+ {
+ /* make nested join structure for view tables */
+ NESTED_JOIN *nested_join;
+ if (!(nested_join= table->nested_join=
+ (NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
+ goto err;
+ nested_join->join_list= view_select->top_join_list;
+
+ /* re-nest tables of VIEW */
+ {
+ List_iterator_fast<TABLE_LIST> ti(nested_join->join_list);
+ while(tbl= ti++)
+ {
+ tbl->join_list= &nested_join->join_list;
+ tbl->embedding= table;
+ }
+ }
+ }
/* Store WHERE clause for post-processing in setup_ancestor */
- table->where= lex->select_lex.where;
+ table->where= view_select->where;
/*
Add subqueries units to SELECT in which we merging current view.
@@ -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);
}
diff --git a/sql/sql_view.h b/sql/sql_view.h
index 538f548d97b..e6f2caeaead 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -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);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 309a9249d0e..a9485436770 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4881,11 +4881,11 @@ when_list2:
table_ref:
table_factor { $$=$1; }
| join_table { $$=$1; }
- {
+ {
LEX *lex= Lex;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
YYABORT;
- }
+ }
;
join_table_list:
@@ -4975,20 +4975,20 @@ table_factor:
sel->get_use_index(),
sel->get_ignore_index())))
YYABORT;
- sel->add_joined_table($$);
+ sel->add_joined_table($$);
}
| '('
- {
+ {
LEX *lex= Lex;
if (lex->current_select->init_nested_join(lex->thd))
YYABORT;
- }
+ }
join_table_list ')'
{
LEX *lex= Lex;
if (!($$= lex->current_select->end_nested_join(lex->thd)))
YYABORT;
- }
+ }
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
| '(' SELECT_SYM select_derived ')' opt_table_alias
diff --git a/sql/table.cc b/sql/table.cc
index 0e8045abacf..74e35e0f2d7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -1517,10 +1517,65 @@ void st_table_list::calc_md5(char *buffer)
void st_table_list::set_ancestor()
{
- if (ancestor->ancestor)
- ancestor->set_ancestor();
- table= ancestor->table;
- ancestor->table->grant= grant;
+ /* process all tables of view */
+ for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->ancestor)
+ ancestor->set_ancestor();
+ tbl->table->grant= grant;
+ }
+ /* if view contain only one table, substitute TABLE of it */
+ if (!ancestor->next_local)
+ table= ancestor->table;
+}
+
+
+/*
+ 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,
- (check_opt_type == VIEW_CHECK_CASCADED ?
- VIEW_CHECK_CASCADED :
- VIEW_CHECK_NONE)))
- DBUG_RETURN(1);
+ for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->ancestor &&
+ tbl->setup_ancestor(thd, conds,
+ (check_opt_type == VIEW_CHECK_CASCADED ?
+ VIEW_CHECK_CASCADED :
+ VIEW_CHECK_NONE)))
+ DBUG_RETURN(1);
+ }
if (field_translation)
{
/* prevent look up in SELECTs tree */
thd->lex->current_select= &thd->lex->select_lex;
+ thd->lex->select_lex.no_wrap_view_item= 1;
thd->set_query_id= 1;
/* this view was prepared already on previous PS/SP execution */
- Item **end= field_translation + select->item_list.elements;
- for (Item **item= field_translation; item < end; item++)
+ Field_translator *end= field_translation + select->item_list.elements;
+ /* real rights will be checked in VIEW field */
+ save_and_clear_want_privilege();
+ /* aggregate function are allowed */
+ thd->allow_sum_func= 1;
+ for (transl= field_translation; transl < end; transl++)
{
- /* TODO: fix for several tables in VIEW */
- uint want_privilege= ancestor->table->grant.want_privilege;
- /* real rights will be checked in VIEW field */
- ancestor->table->grant.want_privilege= 0;
- /* aggregate function are allowed */
- thd->allow_sum_func= 1;
- if (!(*item)->fixed && (*item)->fix_fields(thd, ancestor, item))
+ if (!transl->item->fixed &&
+ transl->item->fix_fields(thd, ancestor, &transl->item))
goto err;
- ancestor->table->grant.want_privilege= want_privilege;
+ }
+ for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->on_expr && !tbl->on_expr->fixed &&
+ tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
+ goto err;
+ }
+ if (where && !where->fixed && where->fix_fields(thd, ancestor, &where))
+ goto err;
+ restore_want_privilege();
+
+ /* WHERE/ON resolved => we can rename fields */
+ for (transl= field_translation; transl < end; transl++)
+ {
+ transl->item->rename((char *)transl->name);
}
goto ok;
}
/* view fields translation table */
if (!(transl=
- (Item**)(thd->current_arena->alloc(select->item_list.elements * sizeof(Item*)))))
+ (Field_translator*)(thd->current_arena->
+ alloc(select->item_list.elements *
+ sizeof(Field_translator)))))
{
DBUG_RETURN(1);
}
@@ -1608,22 +1683,29 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds,
used fields correctly.
*/
thd->set_query_id= 1;
+ /* real rights will be checked in VIEW field */
+ save_and_clear_want_privilege();
+ /* aggregate function are allowed */
+ thd->allow_sum_func= 1;
while ((item= it++))
{
- /* TODO: fix for several tables in VIEW */
- uint want_privilege= ancestor->table->grant.want_privilege;
- /* real rights will be checked in VIEW field */
- ancestor->table->grant.want_privilege= 0;
- /* aggregate function are allowed */
- thd->allow_sum_func= 1;
+ /* save original name of view column */
+ char *name= item->name;
if (!item->fixed && item->fix_fields(thd, ancestor, &item))
goto err;
- ancestor->table->grant.want_privilege= want_privilege;
- transl[i++]= item;
+ /* set new item get in fix fields and original column name */
+ transl[i].name= name;
+ transl[i++].item= item;
}
field_translation= transl;
/* TODO: sort this list? Use hash for big number of fields */
+ for (tbl= ancestor; tbl; tbl= tbl->next_local)
+ {
+ if (tbl->on_expr && !tbl->on_expr->fixed &&
+ tbl->on_expr->fix_fields(thd, ancestor, &tbl->on_expr))
+ goto err;
+ }
if (where ||
(check_opt_type == VIEW_CHECK_CASCADED &&
ancestor->check_option))
@@ -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;
}
diff --git a/sql/table.h b/sql/table.h
index f95be1fcccb..21ea31f832d 100644
--- a/sql/table.h
+++ b/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; }
};