diff --git a/mysql-test/main/view.result b/mysql-test/main/view.result index a962776a4dc..9cab1b5f7f8 100644 --- a/mysql-test/main/view.result +++ b/mysql-test/main/view.result @@ -7029,3 +7029,49 @@ DROP TABLE t1, t2; # # End of 10.6 tests # +# +# MDEV-29587: Allowing insert into a view with columns that +# are not part the table +# +# view with 2 the same fields +CREATE TABLE table1 (x INT); +CREATE VIEW view1 AS SELECT x, x as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +INSERT INTO view1(x1) VALUES (1); +INSERT INTO view1(x1,x) VALUES (1,1); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +DROP VIEW view1; +DROP TABLE table1; +# view with a field and expression over the field +CREATE TABLE table1 (x INT); +CREATE VIEW view1 AS SELECT x, x + 1 as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +INSERT INTO view1(x1) VALUES (1); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +INSERT INTO view1(x1,x) VALUES (1,1); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +DROP VIEW view1; +DROP TABLE table1; +# view with a field and collation expression over the field +CREATE TABLE table1 (x char(20)); +CREATE VIEW view1 AS SELECT x, x collate latin1_german1_ci as x1 FROM table1; +INSERT INTO view1(x) VALUES ("ua"); +# we can insert in the field with collation +INSERT INTO view1(x1) VALUES ("ua"); +INSERT INTO view1(x1,x) VALUES ("ua","ua"); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +DROP VIEW view1; +DROP TABLE table1; +# view with a field and expression over other field +CREATE TABLE table1 (x INT, y INT); +CREATE VIEW view1 AS SELECT x, y + 1 as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +INSERT INTO view1(x1) VALUES (1); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +INSERT INTO view1(x1,x) VALUES (1,1); +ERROR HY000: The target table view1 of the INSERT is not insertable-into +DROP VIEW view1; +DROP TABLE table1; +# +# End of 10.11 test +# diff --git a/mysql-test/main/view.test b/mysql-test/main/view.test index a4fe17a86f7..4c2d71d4906 100644 --- a/mysql-test/main/view.test +++ b/mysql-test/main/view.test @@ -6792,3 +6792,56 @@ DROP TABLE t1, t2; --echo # --echo # End of 10.6 tests --echo # + + +--echo # +--echo # MDEV-29587: Allowing insert into a view with columns that +--echo # are not part the table +--echo # + +--echo # view with 2 the same fields +CREATE TABLE table1 (x INT); +CREATE VIEW view1 AS SELECT x, x as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +INSERT INTO view1(x1) VALUES (1); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1,x) VALUES (1,1); +DROP VIEW view1; +DROP TABLE table1; + +--echo # view with a field and expression over the field +CREATE TABLE table1 (x INT); +CREATE VIEW view1 AS SELECT x, x + 1 as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1) VALUES (1); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1,x) VALUES (1,1); +DROP VIEW view1; +DROP TABLE table1; + +--echo # view with a field and collation expression over the field +CREATE TABLE table1 (x char(20)); +CREATE VIEW view1 AS SELECT x, x collate latin1_german1_ci as x1 FROM table1; +INSERT INTO view1(x) VALUES ("ua"); +--echo # we can insert in the field with collation +INSERT INTO view1(x1) VALUES ("ua"); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1,x) VALUES ("ua","ua"); +DROP VIEW view1; +DROP TABLE table1; + +--echo # view with a field and expression over other field +CREATE TABLE table1 (x INT, y INT); +CREATE VIEW view1 AS SELECT x, y + 1 as x1 FROM table1; +INSERT INTO view1(x) VALUES (1); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1) VALUES (1); +--error ER_NON_INSERTABLE_TABLE +INSERT INTO view1(x1,x) VALUES (1,1); +DROP VIEW view1; +DROP TABLE table1; + +--echo # +--echo # End of 10.11 test +--echo # diff --git a/mysql-test/suite/funcs_1/r/innodb_views.result b/mysql-test/suite/funcs_1/r/innodb_views.result index 90d72b451b9..5bd48cf9706 100644 --- a/mysql-test/suite/funcs_1/r/innodb_views.result +++ b/mysql-test/suite/funcs_1/r/innodb_views.result @@ -22145,9 +22145,9 @@ DELETE FROM t1; DROP VIEW v1; CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; INSERT INTO v1 SET f1 = 1; -ERROR HY000: The target table v1 of the INSERT is not insertable-into SELECT * from t1; f1 f2 f3 f4 +1 NULL NULL NULL DELETE FROM t1; INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO'; ERROR HY000: The target table v1 of the INSERT is not insertable-into diff --git a/mysql-test/suite/funcs_1/r/memory_views.result b/mysql-test/suite/funcs_1/r/memory_views.result index 417c0e85188..8ce1e1c7cba 100644 --- a/mysql-test/suite/funcs_1/r/memory_views.result +++ b/mysql-test/suite/funcs_1/r/memory_views.result @@ -22147,9 +22147,9 @@ DELETE FROM t1; DROP VIEW v1; CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; INSERT INTO v1 SET f1 = 1; -ERROR HY000: The target table v1 of the INSERT is not insertable-into SELECT * from t1; f1 f2 f3 f4 +1 NULL NULL NULL DELETE FROM t1; INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO'; ERROR HY000: The target table v1 of the INSERT is not insertable-into diff --git a/mysql-test/suite/funcs_1/r/myisam_views-big.result b/mysql-test/suite/funcs_1/r/myisam_views-big.result index efd5ee1c568..984ae74fc8b 100644 --- a/mysql-test/suite/funcs_1/r/myisam_views-big.result +++ b/mysql-test/suite/funcs_1/r/myisam_views-big.result @@ -23849,9 +23849,9 @@ DELETE FROM t1; DROP VIEW v1; CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; INSERT INTO v1 SET f1 = 1; -ERROR HY000: The target table v1 of the INSERT is not insertable-into SELECT * from t1; f1 f2 f3 f4 +1 NULL NULL NULL DELETE FROM t1; INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO'; ERROR HY000: The target table v1 of the INSERT is not insertable-into diff --git a/mysql-test/suite/funcs_1/views/views_master.inc b/mysql-test/suite/funcs_1/views/views_master.inc index 526e9e3426e..a9203529f21 100644 --- a/mysql-test/suite/funcs_1/views/views_master.inc +++ b/mysql-test/suite/funcs_1/views/views_master.inc @@ -3479,7 +3479,6 @@ CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; # Maybe the SQL standard allows the following INSERT. # But it would be a very sophisticated DBMS. ---error ER_NON_INSERTABLE_TABLE INSERT INTO v1 SET f1 = 1; SELECT * from t1; DELETE FROM t1; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 7c72d979e75..345f174def2 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -96,7 +96,8 @@ static void end_delayed_insert(THD *thd); pthread_handler_t handle_delayed_insert(void *arg); static void unlink_blobs(TABLE *table); #endif -static bool check_view_insertability(THD *thd, TABLE_LIST *view); +static bool check_view_insertability(THD *thd, TABLE_LIST *view, + List &fields); static int binlog_show_create_table_(THD *thd, TABLE *table, Table_specification_st *create_info); @@ -311,7 +312,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, if (check_key_in_view(thd, table_list) || (table_list->view && - check_view_insertability(thd, table_list))) + check_view_insertability(thd, table_list, fields))) { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias.str, "INSERT"); DBUG_RETURN(-1); @@ -1426,6 +1427,7 @@ abort: check_view_insertability() thd - thread handler view - reference on VIEW + fields - fields used in insert IMPLEMENTATION A view is insertable if the folloings are true: @@ -1441,7 +1443,8 @@ abort: TRUE - can't be used for insert */ -static bool check_view_insertability(THD * thd, TABLE_LIST *view) +static bool check_view_insertability(THD *thd, TABLE_LIST *view, + List &fields) { uint num= view->view->first_select_lex()->item_list.elements; TABLE *table= view->table; @@ -1452,6 +1455,8 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size); MY_BITMAP used_fields; enum_column_usage saved_column_usage= thd->column_usage; + List_iterator_fast it(fields); + Item *ex; DBUG_ENTER("check_key_in_view"); if (!used_fields_buff) @@ -1480,6 +1485,17 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) /* simple SELECT list entry (field without expression) */ if (!(field= trans->item->field_for_view_update())) { + // Do not check fields which we are not inserting into + while((ex= it++)) + { + // The field used in the INSERT + if (ex->real_item()->field_for_view_update() == + trans->item->field_for_view_update()) + break; + } + it.rewind(); + if (!ex) + continue; thd->column_usage= saved_column_usage; DBUG_RETURN(TRUE); } @@ -1494,11 +1510,12 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) } thd->column_usage= saved_column_usage; /* unique test */ - for (trans= trans_start; trans != trans_end; trans++) + while((ex= it++)) { /* Thanks to test above, we know that all columns are of type Item_field */ - Item_field *field= (Item_field *)trans->item; - /* check fields belong to table in which we are inserting */ + DBUG_ASSERT(ex->real_item()->field_for_view_update()->type() == + Item::FIELD_ITEM); + Item_field *field= (Item_field *)ex->real_item()->field_for_view_update(); if (field->field->table == table && bitmap_fast_test_and_set(&used_fields, field->field->field_index)) DBUG_RETURN(TRUE);