Commit 77b10802 authored by Sergey Vojtovich's avatar Sergey Vojtovich

MDEV-4786 - merge 10.0-monty - 10.0

Merged missing changes from revision
alexander.nozdrin@oracle.com-20111219114211-49pqi0wfs9p4o9yi
parent ad97ff88
...@@ -356,25 +356,24 @@ a ...@@ -356,25 +356,24 @@ a
drop view v1; drop view v1;
create view v1 as select a from t2; create view v1 as select a from t2;
set @var=8; set @var=8;
# XXX: bug, the SQL statement in the trigger is still # View in the INSERT-statement in the trigger is still pointing to
# pointing at table 't3', since the view was expanded # table 't3', because the trigger hasn't noticed the change
# at first statement execution. # in view definition. This will be fixed by WL#4179.
# Since the view definition is inlined in the statement #
# at prepare, changing the view definition does not cause # The prepared INSERT-statement however does notice the change,
# repreparation. # but repreparation of the main statement doesn't cause repreparation
# Repreparation of the main statement doesn't cause repreparation
# of trigger statements. # of trigger statements.
#
# The following EXECUTE results in ER_NO_SUCH_TABLE (t3) error, because
# pre-locking list of the prepared statement has been changed
# (the prepared statement has noticed the meta-data change),
# but the trigger still tries to deal with 't3', which is not opened.
# That's why '8' is not inserted neither into 't2', nor into 't3'.
execute stmt using @var; execute stmt using @var;
call p_verify_reprepare_count(0); ERROR 42S02: Table 'test.t3' doesn't exist
call p_verify_reprepare_count(1);
SUCCESS SUCCESS
#
# Sic: the insert went into t3, even though the view now
# points at t2. This is because neither the merged view
# nor its prelocking list are affected by view DDL
# The binary log is of course wrong, since it is not
# using prepared statements
#
select * from t2; select * from t2;
a a
5 5
...@@ -382,7 +381,6 @@ select * from t3; ...@@ -382,7 +381,6 @@ select * from t3;
a a
6 6
7 7
8
flush table t1; flush table t1;
set @var=9; set @var=9;
execute stmt using @var; execute stmt using @var;
...@@ -397,7 +395,6 @@ select * from t3; ...@@ -397,7 +395,6 @@ select * from t3;
a a
6 6
7 7
8
drop view v1; drop view v1;
drop table t1,t2,t3; drop table t1,t2,t3;
# Test 7-d: dependent TABLE has changed # Test 7-d: dependent TABLE has changed
...@@ -817,17 +814,14 @@ a b c ...@@ -817,17 +814,14 @@ a b c
10 20 50 10 20 50
20 40 100 20 40 100
30 60 150 30 60 150
# Currently a different result from conventional statements. # This is actually a test case for Bug#11748352 (36002 Prepared
# A view is inlined once at prepare, later on view DDL # statements: if a view used in a statement is replaced, bad data).
# does not affect prepared statement and it is not re-prepared.
# This is reported in Bug#36002 Prepared statements: if a view
# used in a statement is replaced, bad data
execute stmt; execute stmt;
a b c a b c
10 20 30 10 20 50
20 40 60 20 40 100
30 60 90 30 60 150
call p_verify_reprepare_count(0); call p_verify_reprepare_count(1);
SUCCESS SUCCESS
flush table t2; flush table t2;
...@@ -839,9 +833,200 @@ a b c ...@@ -839,9 +833,200 @@ a b c
call p_verify_reprepare_count(1); call p_verify_reprepare_count(1);
SUCCESS SUCCESS
# Check that we properly handle ALTER VIEW statements.
execute stmt;
a b c
10 20 50
20 40 100
30 60 150
call p_verify_reprepare_count(0);
SUCCESS
alter view t1 as select a, 3*a as b, 4*a as c from t2;
execute stmt;
a b c
10 30 40
20 60 80
30 90 120
call p_verify_reprepare_count(1);
SUCCESS
execute stmt;
a b c
10 30 40
20 60 80
30 90 120
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a b c
10 30 40
20 60 80
30 90 120
call p_verify_reprepare_count(0);
SUCCESS
select * from t1;
a b c
10 30 40
20 60 80
30 90 120
# Check that DROP & CREATE is properly handled under LOCK TABLES.
drop view t1;
flush tables;
create view t1 as select a, 5*a as b, 6*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
a b c
10 50 60
20 100 120
30 150 180
call p_verify_reprepare_count(1);
SUCCESS
execute stmt;
a b c
10 50 60
20 100 120
30 150 180
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a b c
10 50 60
20 100 120
30 150 180
call p_verify_reprepare_count(0);
SUCCESS
unlock tables;
# ... and once again...
drop view t1;
create view t1 as select a, 6*a as b, 7*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
a b c
10 60 70
20 120 140
30 180 210
call p_verify_reprepare_count(1);
SUCCESS
execute stmt;
a b c
10 60 70
20 120 140
30 180 210
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a b c
10 60 70
20 120 140
30 180 210
call p_verify_reprepare_count(0);
SUCCESS
unlock tables;
# Check that ALTER VIEW is properly handled under LOCK TABLES.
alter view t1 as select a, 7*a as b, 8*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
a b c
10 70 80
20 140 160
30 210 240
call p_verify_reprepare_count(1);
SUCCESS
execute stmt;
a b c
10 70 80
20 140 160
30 210 240
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a b c
10 70 80
20 140 160
30 210 240
call p_verify_reprepare_count(0);
SUCCESS
unlock tables;
drop table t2; drop table t2;
drop view t1; drop view t1;
deallocate prepare stmt; deallocate prepare stmt;
# Check that DROP & CREATE is properly handled under LOCK TABLES when
# LOCK TABLES does not contain the complete set of views.
create table t1(a int);
insert into t1 values (1), (2), (3);
create view v1 as select a from t1;
lock tables t1 read, v1 read;
prepare stmt from 'select * from v1';
execute stmt;
a
1
2
3
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a
1
2
3
call p_verify_reprepare_count(0);
SUCCESS
unlock tables;
drop view v1;
create view v1 as select 2*a from t1;
lock tables t1 read;
execute stmt;
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
unlock tables;
drop table t1;
drop view v1;
deallocate prepare stmt;
# Check that ALTER VIEW is properly handled under LOCK TABLES when
# LOCK TABLES does not contain the complete set of views.
create table t1(a int);
insert into t1 values (1), (2), (3);
create view v1 as select a from t1;
lock tables t1 read, v1 read;
prepare stmt from 'select * from v1';
execute stmt;
a
1
2
3
call p_verify_reprepare_count(0);
SUCCESS
execute stmt;
a
1
2
3
call p_verify_reprepare_count(0);
SUCCESS
unlock tables;
alter view v1 as select 2*a from t1;
lock tables t1 read;
execute stmt;
ERROR HY000: Table 'v1' was not locked with LOCK TABLES
unlock tables;
drop table t1;
drop view v1;
deallocate prepare stmt;
===================================================================== =====================================================================
Part 18: VIEW -> VIEW (VIEW dependencies) transitions Part 18: VIEW -> VIEW (VIEW dependencies) transitions
===================================================================== =====================================================================
...@@ -939,15 +1124,15 @@ drop view v2; ...@@ -939,15 +1124,15 @@ drop view v2;
create view v2 as select a from t2; create view v2 as select a from t2;
execute stmt; execute stmt;
a a
1 4
2 5
3 6
execute stmt; execute stmt;
a a
1 4
2 5
3 6
call p_verify_reprepare_count(0); call p_verify_reprepare_count(1);
SUCCESS SUCCESS
flush table t1; flush table t1;
...@@ -956,7 +1141,7 @@ a ...@@ -956,7 +1141,7 @@ a
4 4
5 5
6 6
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
SUCCESS SUCCESS
execute stmt; execute stmt;
......
...@@ -353,23 +353,22 @@ select * from t2; ...@@ -353,23 +353,22 @@ select * from t2;
drop view v1; drop view v1;
create view v1 as select a from t2; create view v1 as select a from t2;
set @var=8; set @var=8;
--echo # XXX: bug, the SQL statement in the trigger is still --echo # View in the INSERT-statement in the trigger is still pointing to
--echo # pointing at table 't3', since the view was expanded --echo # table 't3', because the trigger hasn't noticed the change
--echo # at first statement execution. --echo # in view definition. This will be fixed by WL#4179.
--echo # Since the view definition is inlined in the statement
--echo # at prepare, changing the view definition does not cause
--echo # repreparation.
--echo # Repreparation of the main statement doesn't cause repreparation
--echo # of trigger statements.
execute stmt using @var;
call p_verify_reprepare_count(0);
--echo # --echo #
--echo # Sic: the insert went into t3, even though the view now --echo # The prepared INSERT-statement however does notice the change,
--echo # points at t2. This is because neither the merged view --echo # but repreparation of the main statement doesn't cause repreparation
--echo # nor its prelocking list are affected by view DDL --echo # of trigger statements.
--echo # The binary log is of course wrong, since it is not
--echo # using prepared statements
--echo # --echo #
--echo # The following EXECUTE results in ER_NO_SUCH_TABLE (t3) error, because
--echo # pre-locking list of the prepared statement has been changed
--echo # (the prepared statement has noticed the meta-data change),
--echo # but the trigger still tries to deal with 't3', which is not opened.
--echo # That's why '8' is not inserted neither into 't2', nor into 't3'.
--error ER_NO_SUCH_TABLE
execute stmt using @var;
call p_verify_reprepare_count(1);
select * from t2; select * from t2;
select * from t3; select * from t3;
flush table t1; flush table t1;
...@@ -736,21 +735,136 @@ drop view t1; ...@@ -736,21 +735,136 @@ drop view t1;
create view t1 as select a, 2*a as b, 5*a as c from t2; create view t1 as select a, 2*a as b, 5*a as c from t2;
select * from t1; select * from t1;
--echo # Currently a different result from conventional statements. --echo # This is actually a test case for Bug#11748352 (36002 Prepared
--echo # A view is inlined once at prepare, later on view DDL --echo # statements: if a view used in a statement is replaced, bad data).
--echo # does not affect prepared statement and it is not re-prepared.
--echo # This is reported in Bug#36002 Prepared statements: if a view
--echo # used in a statement is replaced, bad data
execute stmt; execute stmt;
call p_verify_reprepare_count(0); call p_verify_reprepare_count(1);
flush table t2; flush table t2;
execute stmt;
call p_verify_reprepare_count(1);
--echo # Check that we properly handle ALTER VIEW statements.
execute stmt;
call p_verify_reprepare_count(0);
alter view t1 as select a, 3*a as b, 4*a as c from t2;
execute stmt;
call p_verify_reprepare_count(1);
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
select * from t1;
--echo # Check that DROP & CREATE is properly handled under LOCK TABLES.
drop view t1;
flush tables; # empty TDC
create view t1 as select a, 5*a as b, 6*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
call p_verify_reprepare_count(1);
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
unlock tables;
--echo # ... and once again...
drop view t1;
create view t1 as select a, 6*a as b, 7*a as c from t2;
lock tables t1 read, t2 read;
execute stmt; execute stmt;
call p_verify_reprepare_count(1); call p_verify_reprepare_count(1);
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
unlock tables;
--echo # Check that ALTER VIEW is properly handled under LOCK TABLES.
alter view t1 as select a, 7*a as b, 8*a as c from t2;
lock tables t1 read, t2 read;
execute stmt;
call p_verify_reprepare_count(1);
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
unlock tables;
drop table t2; drop table t2;
drop view t1; drop view t1;
deallocate prepare stmt; deallocate prepare stmt;
--echo # Check that DROP & CREATE is properly handled under LOCK TABLES when
--echo # LOCK TABLES does not contain the complete set of views.
create table t1(a int);
insert into t1 values (1), (2), (3);
create view v1 as select a from t1;
lock tables t1 read, v1 read;
prepare stmt from 'select * from v1';
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
unlock tables;
drop view v1;
create view v1 as select 2*a from t1;
# Miss v1.
lock tables t1 read;
--error ER_TABLE_NOT_LOCKED
execute stmt;
unlock tables;
drop table t1;
drop view v1;
deallocate prepare stmt;
--echo # Check that ALTER VIEW is properly handled under LOCK TABLES when
--echo # LOCK TABLES does not contain the complete set of views.
create table t1(a int);
insert into t1 values (1), (2), (3);
create view v1 as select a from t1;
lock tables t1 read, v1 read;
prepare stmt from 'select * from v1';
execute stmt;
call p_verify_reprepare_count(0);
execute stmt;
call p_verify_reprepare_count(0);
unlock tables;
alter view v1 as select 2*a from t1;
# Miss v1.
lock tables t1 read;
--error ER_TABLE_NOT_LOCKED
execute stmt;
unlock tables;
drop table t1;
drop view v1;
deallocate prepare stmt;
--echo ===================================================================== --echo =====================================================================
--echo Part 18: VIEW -> VIEW (VIEW dependencies) transitions --echo Part 18: VIEW -> VIEW (VIEW dependencies) transitions
--echo ===================================================================== --echo =====================================================================
...@@ -819,10 +933,10 @@ drop view v2; ...@@ -819,10 +933,10 @@ drop view v2;
create view v2 as select a from t2; create view v2 as select a from t2;
execute stmt; execute stmt;
execute stmt; execute stmt;
call p_verify_reprepare_count(0); call p_verify_reprepare_count(1);
flush table t1; flush table t1;
execute stmt; execute stmt;
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
execute stmt; execute stmt;
--echo # Test 18-d: dependent TABLE has changed --echo # Test 18-d: dependent TABLE has changed
drop view v2; drop view v2;
......
...@@ -667,6 +667,15 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, ...@@ -667,6 +667,15 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
res= mysql_register_view(thd, view, mode); res= mysql_register_view(thd, view, mode);
/*
View TABLE_SHARE must be removed from the table definition cache in order to
make ALTER VIEW work properly. Otherwise, we would not be able to detect
meta-data changes after ALTER VIEW.
*/
if (!res)
tdc_remove_table(thd, TDC_RT_REMOVE_ALL, view->db, view->table_name, false);
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
String buff; String buff;
......
...@@ -865,7 +865,7 @@ struct TABLE_SHARE ...@@ -865,7 +865,7 @@ struct TABLE_SHARE
} }
/** /**
Return a table metadata version. Return a table metadata version.
* for base tables, we return table_map_id. * for base tables and views, we return table_map_id.
It is assigned from a global counter incremented for each It is assigned from a global counter incremented for each
new table loaded into the table definition cache (TDC). new table loaded into the table definition cache (TDC).
* for temporary tables it's table_map_id again. But for * for temporary tables it's table_map_id again. But for
...@@ -874,7 +874,7 @@ struct TABLE_SHARE ...@@ -874,7 +874,7 @@ struct TABLE_SHARE
counter incremented for every new SQL statement. Since counter incremented for every new SQL statement. Since
temporary tables are thread-local, each temporary table temporary tables are thread-local, each temporary table
gets a unique id. gets a unique id.
* for everything else (views, information schema tables), * for everything else (e.g. information schema tables),
the version id is zero. the version id is zero.
This choice of version id is a large compromise This choice of version id is a large compromise
...@@ -889,8 +889,8 @@ struct TABLE_SHARE ...@@ -889,8 +889,8 @@ struct TABLE_SHARE
version id of a temporary table is never compared with version id of a temporary table is never compared with
a version id of a view, and vice versa. a version id of a view, and vice versa.
Secondly, for base tables, we know that each DDL flushes the Secondly, for base tables and views, we know that each DDL flushes
respective share from the TDC. This ensures that whenever the respective share from the TDC. This ensures that whenever
a table is altered or dropped and recreated, it gets a new a table is altered or dropped and recreated, it gets a new
version id. version id.
Unfortunately, since elements of the TDC are also flushed on Unfortunately, since elements of the TDC are also flushed on
...@@ -911,26 +911,6 @@ struct TABLE_SHARE ...@@ -911,26 +911,6 @@ struct TABLE_SHARE
Metadata of information schema tables never changes. Metadata of information schema tables never changes.
Thus we can safely assume 0 for a good enough version id. Thus we can safely assume 0 for a good enough version id.
Views are a special and tricky case. A view is always inlined
into the parse tree of a prepared statement at prepare.
Thus, when we execute a prepared statement, the parse tree
will not get modified even if the view is replaced with another
view. Therefore, we can safely choose 0 for version id of
views and effectively never invalidate a prepared statement
when a view definition is altered. Note, that this leads to
wrong binary log in statement-based replication, since we log
prepared statement execution in form Query_log_events
containing conventional statements. But since there is no
metadata locking for views, the very same problem exists for
conventional statements alone, as reported in Bug#25144. The only
difference between prepared and conventional execution is,
effectively, that for prepared statements the race condition
window is much wider.
In 6.0 we plan to support view metadata locking (WL#3726) and
extend table definition cache to cache views (WL#4298).
When this is done, views will be handled in the same fashion
as the base tables.
Finally, by taking into account table type, we always Finally, by taking into account table type, we always
track that a change has taken place when a view is replaced track that a change has taken place when a view is replaced
with a base table, a base table is replaced with a temporary with a base table, a base table is replaced with a temporary
...@@ -940,7 +920,7 @@ struct TABLE_SHARE ...@@ -940,7 +920,7 @@ struct TABLE_SHARE
*/ */
ulong get_table_ref_version() const ulong get_table_ref_version() const
{ {
return (tmp_table == SYSTEM_TMP_TABLE || is_view) ? 0 : table_map_id; return (tmp_table == SYSTEM_TMP_TABLE) ? 0 : table_map_id;
} }
bool visit_subgraph(Wait_for_flush *waiting_ticket, bool visit_subgraph(Wait_for_flush *waiting_ticket,
......
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