Commit d6e1377a authored by unknown's avatar unknown

Fix check of view updatability in case of underlying view changes its updatability.

For single table update/insert added deep check of single tables (single_table_updatable()).
For multi-table view insert added additional check of target table (check_view_single_update).
Multi-update was correct.

Test suite for all cases added.
parent 81690cf3
...@@ -3930,10 +3930,35 @@ drop table t1,t2; ...@@ -3930,10 +3930,35 @@ drop table t1,t2;
# Bug #794005: crash in st_table::mark_virtual_columns_for_write # Bug #794005: crash in st_table::mark_virtual_columns_for_write
# #
CREATE TABLE t1 (a int); CREATE TABLE t1 (a int);
insert into t1 values (1);
CREATE TABLE t2 (a int); CREATE TABLE t2 (a int);
insert into t2 values (1);
CREATE VIEW v2 AS SELECT * FROM t2; CREATE VIEW v2 AS SELECT * FROM t2;
CREATE VIEW v1 AS SELECT * FROM v2; CREATE VIEW v1 AS SELECT * FROM v2;
CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a;
CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1;
UPDATE v1 SET a = 10; UPDATE v1 SET a = 10;
DROP VIEW v1,v2; ERROR HY000: The target table v1 of the UPDATE is not updatable
REPLACE v1 SET a = 10;
ERROR HY000: The target table v1 of the INSERT is not insertable-into
INSERT into v1 values (20);
ERROR HY000: The target table v1 of the INSERT is not insertable-into
UPDATE v3 SET b= 10;
ERROR HY000: The target table v2 of the UPDATE is not updatable
REPLACE v3 SET b= 10;
ERROR HY000: The target table v3 of the INSERT is not insertable-into
INSERT into v3(b) values (20);
ERROR HY000: The target table v3 of the INSERT is not insertable-into
UPDATE v3 SET a = 10;
REPLACE v3 SET a = 11;
INSERT INTO v3(a) values (20);
select * from t1;
a
1
select * from t2;
a
10
11
20
DROP VIEW v1,v2,v3;
DROP TABLE t1,t2; DROP TABLE t1,t2;
...@@ -3982,13 +3982,33 @@ drop table t1,t2; ...@@ -3982,13 +3982,33 @@ drop table t1,t2;
--echo # --echo #
CREATE TABLE t1 (a int); CREATE TABLE t1 (a int);
insert into t1 values (1);
CREATE TABLE t2 (a int); CREATE TABLE t2 (a int);
insert into t2 values (1);
CREATE VIEW v2 AS SELECT * FROM t2; CREATE VIEW v2 AS SELECT * FROM t2;
CREATE VIEW v1 AS SELECT * FROM v2; CREATE VIEW v1 AS SELECT * FROM v2;
CREATE VIEW v3 AS SELECT t2.a,v1.a as b FROM t2,v1 where t2.a=v1.a;
CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1; CREATE OR REPLACE ALGORITHM = TEMPTABLE VIEW v2 AS SELECT * FROM t1;
--error ER_NON_UPDATABLE_TABLE
UPDATE v1 SET a = 10; UPDATE v1 SET a = 10;
--error ER_NON_INSERTABLE_TABLE
REPLACE v1 SET a = 10;
--error ER_NON_INSERTABLE_TABLE
INSERT into v1 values (20);
--error ER_NON_UPDATABLE_TABLE
UPDATE v3 SET b= 10;
--error ER_NON_INSERTABLE_TABLE
REPLACE v3 SET b= 10;
--error ER_NON_INSERTABLE_TABLE
INSERT into v3(b) values (20);
UPDATE v3 SET a = 10;
REPLACE v3 SET a = 11;
INSERT INTO v3(a) values (20);
DROP VIEW v1,v2; select * from t1;
select * from t2;
DROP VIEW v1,v2,v3;
DROP TABLE t1,t2; DROP TABLE t1,t2;
...@@ -103,7 +103,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view); ...@@ -103,7 +103,8 @@ static bool check_view_insertability(THD *thd, TABLE_LIST *view);
*/ */
bool check_view_single_update(List<Item> &fields, List<Item> *values, bool check_view_single_update(List<Item> &fields, List<Item> *values,
TABLE_LIST *view, table_map *map) TABLE_LIST *view, table_map *map,
bool insert)
{ {
/* it is join view => we need to find the table for update */ /* it is join view => we need to find the table for update */
List_iterator_fast<Item> it(fields); List_iterator_fast<Item> it(fields);
...@@ -135,6 +136,14 @@ bool check_view_single_update(List<Item> &fields, List<Item> *values, ...@@ -135,6 +136,14 @@ bool check_view_single_update(List<Item> &fields, List<Item> *values,
goto error; goto error;
view->table= tbl->table; view->table= tbl->table;
if (!tbl->single_table_updatable())
{
if (insert)
my_error(ER_NON_INSERTABLE_TABLE, MYF(0), view->alias, "INSERT");
else
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), view->alias, "UPDATE");
return TRUE;
}
*map= tables; *map= tables;
return FALSE; return FALSE;
...@@ -179,7 +188,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, ...@@ -179,7 +188,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
{ {
TABLE *table= table_list->table; TABLE *table= table_list->table;
if (!table_list->updatable) if (!table_list->single_table_updatable())
{ {
my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT");
return -1; return -1;
...@@ -251,7 +260,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, ...@@ -251,7 +260,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (check_view_single_update(fields, if (check_view_single_update(fields,
fields_and_values_from_different_maps ? fields_and_values_from_different_maps ?
(List<Item>*) 0 : &values, (List<Item>*) 0 : &values,
table_list, map)) table_list, map, true))
return -1; return -1;
table= table_list->table; table= table_list->table;
} }
...@@ -337,7 +346,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, ...@@ -337,7 +346,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
check_view_single_update(update_fields, &update_values, check_view_single_update(update_fields, &update_values,
insert_table_list, map)) insert_table_list, map, false))
return -1; return -1;
if (table->timestamp_field) if (table->timestamp_field)
......
...@@ -277,7 +277,8 @@ int mysql_update(THD *thd, ...@@ -277,7 +277,8 @@ int mysql_update(THD *thd,
{ {
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (!table_list->updatable || check_key_in_view(thd, table_list)) if (!table_list->single_table_updatable() ||
check_key_in_view(thd, table_list))
{ {
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE"); my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
DBUG_RETURN(1); DBUG_RETURN(1);
......
...@@ -3722,6 +3722,28 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, ...@@ -3722,6 +3722,28 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
/**
Check that table/view is updatable and if it has single
underlying tables/views it is also updatable
@return Result of the check.
*/
bool TABLE_LIST::single_table_updatable()
{
if (!updatable)
return false;
if (view_tables && view_tables->elements == 1)
{
/*
We need to check deeply only single table views. Multi-table views
will be turned to multi-table updates and then checked by leaf tables
*/
return view_tables->head()->single_table_updatable();
}
return true;
}
/* /*
Merge ON expressions for a view Merge ON expressions for a view
......
...@@ -1606,6 +1606,9 @@ struct TABLE_LIST ...@@ -1606,6 +1606,9 @@ struct TABLE_LIST
*/ */
char *get_table_name() { return view != NULL ? view_name.str : table_name; } char *get_table_name() { return view != NULL ? view_name.str : table_name; }
bool single_table_updatable();
private: private:
bool prep_check_option(THD *thd, uint8 check_opt_type); bool prep_check_option(THD *thd, uint8 check_opt_type);
bool prep_where(THD *thd, Item **conds, bool no_where_clause); bool prep_where(THD *thd, Item **conds, bool no_where_clause);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment