Commit 8c5db7a1 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-29587 Allowing insert into a view with columns that are not part the table

We can check only fields which take part in inserts.
parent bc2f1550
...@@ -7029,3 +7029,49 @@ DROP TABLE t1, t2; ...@@ -7029,3 +7029,49 @@ DROP TABLE t1, t2;
# #
# End of 10.6 tests # 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
#
...@@ -6792,3 +6792,56 @@ DROP TABLE t1, t2; ...@@ -6792,3 +6792,56 @@ DROP TABLE t1, t2;
--echo # --echo #
--echo # End of 10.6 tests --echo # End of 10.6 tests
--echo # --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 #
...@@ -22145,9 +22145,9 @@ DELETE FROM t1; ...@@ -22145,9 +22145,9 @@ DELETE FROM t1;
DROP VIEW v1; DROP VIEW v1;
CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1;
INSERT INTO v1 SET f1 = 1; INSERT INTO v1 SET f1 = 1;
ERROR HY000: The target table v1 of the INSERT is not insertable-into
SELECT * from t1; SELECT * from t1;
f1 f2 f3 f4 f1 f2 f3 f4
1 NULL NULL NULL
DELETE FROM t1; DELETE FROM t1;
INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO'; INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO';
ERROR HY000: The target table v1 of the INSERT is not insertable-into ERROR HY000: The target table v1 of the INSERT is not insertable-into
......
...@@ -22147,9 +22147,9 @@ DELETE FROM t1; ...@@ -22147,9 +22147,9 @@ DELETE FROM t1;
DROP VIEW v1; DROP VIEW v1;
CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1;
INSERT INTO v1 SET f1 = 1; INSERT INTO v1 SET f1 = 1;
ERROR HY000: The target table v1 of the INSERT is not insertable-into
SELECT * from t1; SELECT * from t1;
f1 f2 f3 f4 f1 f2 f3 f4
1 NULL NULL NULL
DELETE FROM t1; DELETE FROM t1;
INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO'; INSERT INTO v1 SET f1 = 1, my_greeting = 'HELLO';
ERROR HY000: The target table v1 of the INSERT is not insertable-into ERROR HY000: The target table v1 of the INSERT is not insertable-into
......
...@@ -3479,7 +3479,6 @@ CREATE VIEW v1 AS SELECT f1, f2, f3, 'HELLO' AS my_greeting FROM t1; ...@@ -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. # Maybe the SQL standard allows the following INSERT.
# But it would be a very sophisticated DBMS. # But it would be a very sophisticated DBMS.
--error ER_NON_INSERTABLE_TABLE
INSERT INTO v1 SET f1 = 1; INSERT INTO v1 SET f1 = 1;
SELECT * from t1; SELECT * from t1;
DELETE FROM t1; DELETE FROM t1;
......
...@@ -96,7 +96,8 @@ static void end_delayed_insert(THD *thd); ...@@ -96,7 +96,8 @@ static void end_delayed_insert(THD *thd);
pthread_handler_t handle_delayed_insert(void *arg); pthread_handler_t handle_delayed_insert(void *arg);
static void unlink_blobs(TABLE *table); static void unlink_blobs(TABLE *table);
#endif #endif
static bool check_view_insertability(THD *thd, TABLE_LIST *view); static bool check_view_insertability(THD *thd, TABLE_LIST *view,
List<Item> &fields);
static int binlog_show_create_table_(THD *thd, TABLE *table, static int binlog_show_create_table_(THD *thd, TABLE *table,
Table_specification_st *create_info); Table_specification_st *create_info);
...@@ -311,7 +312,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, ...@@ -311,7 +312,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list,
if (check_key_in_view(thd, table_list) || if (check_key_in_view(thd, table_list) ||
(table_list->view && (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"); my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias.str, "INSERT");
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -1426,6 +1427,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, ...@@ -1426,6 +1427,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
check_view_insertability() check_view_insertability()
thd - thread handler thd - thread handler
view - reference on VIEW view - reference on VIEW
fields - fields used in insert
IMPLEMENTATION IMPLEMENTATION
A view is insertable if the folloings are true: A view is insertable if the folloings are true:
...@@ -1441,7 +1443,8 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, ...@@ -1441,7 +1443,8 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
TRUE - can't be used for insert 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<Item> &fields)
{ {
uint num= view->view->first_select_lex()->item_list.elements; uint num= view->view->first_select_lex()->item_list.elements;
TABLE *table= view->table; TABLE *table= view->table;
...@@ -1452,6 +1455,8 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) ...@@ -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); uint32 *used_fields_buff= (uint32*)thd->alloc(used_fields_buff_size);
MY_BITMAP used_fields; MY_BITMAP used_fields;
enum_column_usage saved_column_usage= thd->column_usage; enum_column_usage saved_column_usage= thd->column_usage;
List_iterator_fast<Item> it(fields);
Item *ex;
DBUG_ENTER("check_key_in_view"); DBUG_ENTER("check_key_in_view");
if (!used_fields_buff) if (!used_fields_buff)
...@@ -1480,6 +1485,17 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) ...@@ -1480,6 +1485,17 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
/* simple SELECT list entry (field without expression) */ /* simple SELECT list entry (field without expression) */
if (!(field= trans->item->field_for_view_update())) 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; thd->column_usage= saved_column_usage;
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
...@@ -1494,11 +1510,12 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view) ...@@ -1494,11 +1510,12 @@ static bool check_view_insertability(THD * thd, TABLE_LIST *view)
} }
thd->column_usage= saved_column_usage; thd->column_usage= saved_column_usage;
/* unique test */ /* 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 */ /* Thanks to test above, we know that all columns are of type Item_field */
Item_field *field= (Item_field *)trans->item; DBUG_ASSERT(ex->real_item()->field_for_view_update()->type() ==
/* check fields belong to table in which we are inserting */ Item::FIELD_ITEM);
Item_field *field= (Item_field *)ex->real_item()->field_for_view_update();
if (field->field->table == table && if (field->field->table == table &&
bitmap_fast_test_and_set(&used_fields, field->field->field_index)) bitmap_fast_test_and_set(&used_fields, field->field->field_index))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
......
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