Commit 469ff92d authored by unknown's avatar unknown

Bug#19111: TRIGGERs selecting from a VIEW on the firing base table fail.

In a trigger or a function used in a statement it is possible to do
SELECT from a table being modified by the statement.  However,
encapsulation of such SELECT into a view and selecting from a view
instead of direct SELECT was not possible.

This happened because tables used by views (which in their turn
were used from functions/triggers) were not excluded from checks
in unique_table() routine as it happens for the rest of tables
added to the statement table list for prelocking.

With this fix we ignore all such tables in unique_table(), thus
providing consistency: inside a trigger or a functions SELECT from
a view may be used where plain SELECT is allowed.  Modification of
the same table from function or trigger is still disallowed.  Also,
this patch doesn't affect the case where SELECT from the table being
modified is done outside of function of trigger, such SELECTs are
still disallowed (this limitation and visibility problem when function
select from a table being modified are subjects of bug 21326).  See
also bug 22427.


mysql-test/r/view.result:
  Add result for bug#19111: TRIGGERs selecting from a VIEW on the
  firing base table fail.
mysql-test/t/view.test:
  Add test case for bug#19111: TRIGGERs selecting from a VIEW on the
  firing base table fail.
sql/sql_base.cc:
  In unique_table() do not check tables that are used in a stored
  function or a trigger ('prelocking_placeholder' is set).  If such
  function or a trigger will attempt to modify a table, the error will
  be given, however select is allowed there.
parent 44a40f1d
......@@ -2735,4 +2735,19 @@ m e
4 a
1 b
DROP VIEW v1;
DROP TABLE IF EXISTS t1,t2;
DROP TABLE t1,t2;
DROP FUNCTION IF EXISTS f1;
DROP VIEW IF EXISTS v1;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1);
CREATE VIEW v1 AS SELECT MAX(i) FROM t1;
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.i = (SELECT * FROM v1) + 1;
INSERT INTO t1 VALUES (1);
CREATE FUNCTION f1() RETURNS INT RETURN (SELECT * FROM v1);
UPDATE t1 SET i= f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
End of 5.0 tests.
......@@ -2595,4 +2595,41 @@ CREATE TABLE t2 SELECT * FROM v1;
SELECT * FROM t2;
DROP VIEW v1;
DROP TABLE IF EXISTS t1,t2;
DROP TABLE t1,t2;
#
# Bug#19111: TRIGGERs selecting from a VIEW on the firing base table
# fail
#
# Allow to select from a view on a table being modified in a trigger
# and stored function, since plain select is allowed there.
#
--disable_warnings
DROP FUNCTION IF EXISTS f1;
DROP VIEW IF EXISTS v1;
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1);
CREATE VIEW v1 AS SELECT MAX(i) FROM t1;
# Plain 'SET NEW.i = (SELECT MAX(i) FROM t1) + 1' works, so select
# from a view should work too.
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.i = (SELECT * FROM v1) + 1;
INSERT INTO t1 VALUES (1);
# Plain 'RETURN (SELECT MAX(i) FROM t1)' works in INSERT, so select
# from a view should work too.
CREATE FUNCTION f1() RETURNS INT RETURN (SELECT * FROM v1);
UPDATE t1 SET i= f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
--echo End of 5.0 tests.
......@@ -805,6 +805,10 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
Also SELECT::exclude_from_table_unique_test used to exclude from check
tables of main SELECT of multi-delete and multi-update
We also skip tables with TABLE_LIST::prelocking_placeholder set,
because we want to allow SELECTs from them, and their modification
will rise the error anyway.
TODO: when we will have table/view change detection we can do this check
only once for PS/SP
......@@ -851,12 +855,13 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
((!res->table || res->table != table->table) &&
res->select_lex && !res->select_lex->exclude_from_table_unique_test))
res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
!res->prelocking_placeholder))
break;
/*
If we found entry of this table or or table of SELECT which already
If we found entry of this table or table of SELECT which already
processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test).
(exclude_from_table_unique_test) or prelocking placeholder.
*/
table_list= res->next_global;
DBUG_PRINT("info",
......
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