mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
@ -3930,10 +3930,35 @@ drop table t1,t2;
|
||||
# Bug #794005: crash in st_table::mark_virtual_columns_for_write
|
||||
#
|
||||
CREATE TABLE t1 (a int);
|
||||
insert into t1 values (1);
|
||||
CREATE TABLE t2 (a int);
|
||||
insert into t2 values (1);
|
||||
CREATE VIEW v2 AS SELECT * FROM t2;
|
||||
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;
|
||||
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;
|
||||
|
@ -3982,13 +3982,33 @@ drop table t1,t2;
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a int);
|
||||
insert into t1 values (1);
|
||||
CREATE TABLE t2 (a int);
|
||||
insert into t2 values (1);
|
||||
|
||||
CREATE VIEW v2 AS SELECT * FROM t2;
|
||||
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;
|
||||
|
||||
--error ER_NON_UPDATABLE_TABLE
|
||||
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;
|
||||
|
@ -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,
|
||||
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 */
|
||||
List_iterator_fast<Item> it(fields);
|
||||
@ -135,6 +136,14 @@ bool check_view_single_update(List<Item> &fields, List<Item> *values,
|
||||
goto error;
|
||||
|
||||
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;
|
||||
|
||||
return FALSE;
|
||||
@ -179,7 +188,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
|
||||
{
|
||||
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");
|
||||
return -1;
|
||||
@ -251,7 +260,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
|
||||
if (check_view_single_update(fields,
|
||||
fields_and_values_from_different_maps ?
|
||||
(List<Item>*) 0 : &values,
|
||||
table_list, map))
|
||||
table_list, map, true))
|
||||
return -1;
|
||||
table= table_list->table;
|
||||
}
|
||||
@ -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 &&
|
||||
check_view_single_update(update_fields, &update_values,
|
||||
insert_table_list, map))
|
||||
insert_table_list, map, false))
|
||||
return -1;
|
||||
|
||||
if (table->timestamp_field)
|
||||
|
@ -277,7 +277,8 @@ int mysql_update(THD *thd,
|
||||
{
|
||||
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");
|
||||
DBUG_RETURN(1);
|
||||
|
22
sql/table.cc
22
sql/table.cc
@ -3722,6 +3722,28 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds,
|
||||
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
|
||||
|
@ -1606,6 +1606,9 @@ struct TABLE_LIST
|
||||
*/
|
||||
char *get_table_name() { return view != NULL ? view_name.str : table_name; }
|
||||
|
||||
|
||||
bool single_table_updatable();
|
||||
|
||||
private:
|
||||
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
||||
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
||||
|
Reference in New Issue
Block a user