diff options
author | Sergey Vojtovich <svoj@mariadb.org> | 2013-09-03 16:29:25 +0400 |
---|---|---|
committer | Sergey Vojtovich <svoj@mariadb.org> | 2013-09-03 16:29:25 +0400 |
commit | 77b10802a7ff75299a29d1480dcb1695bbab7e67 (patch) | |
tree | 711d2c74232d9482e17dcc682bc2031b541c68d3 | |
parent | ad97ff888f0939e969ff051da8a489cef97eda3d (diff) | |
download | mariadb-git-77b10802a7ff75299a29d1480dcb1695bbab7e67.tar.gz |
MDEV-4786 - merge 10.0-monty - 10.0
Merged missing changes from revision
alexander.nozdrin@oracle.com-20111219114211-49pqi0wfs9p4o9yi
-rw-r--r-- | mysql-test/r/ps_ddl.result | 253 | ||||
-rw-r--r-- | mysql-test/t/ps_ddl.test | 160 | ||||
-rw-r--r-- | sql/sql_view.cc | 9 | ||||
-rw-r--r-- | sql/table.h | 30 |
4 files changed, 370 insertions, 82 deletions
diff --git a/mysql-test/r/ps_ddl.result b/mysql-test/r/ps_ddl.result index 5f156c170a4..7a8b38bec75 100644 --- a/mysql-test/r/ps_ddl.result +++ b/mysql-test/r/ps_ddl.result @@ -356,25 +356,24 @@ a drop view v1; create view v1 as select a from t2; set @var=8; -# XXX: bug, the SQL statement in the trigger is still -# pointing at table 't3', since the view was expanded -# at first statement execution. -# Since the view definition is inlined in the statement -# at prepare, changing the view definition does not cause -# repreparation. -# Repreparation of the main statement doesn't cause repreparation +# View in the INSERT-statement in the trigger is still pointing to +# table 't3', because the trigger hasn't noticed the change +# in view definition. This will be fixed by WL#4179. +# +# The prepared INSERT-statement however does notice the change, +# but repreparation of the main statement doesn't cause repreparation # 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; -call p_verify_reprepare_count(0); +ERROR 42S02: Table 'test.t3' doesn't exist +call p_verify_reprepare_count(1); 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; a 5 @@ -382,7 +381,6 @@ select * from t3; a 6 7 -8 flush table t1; set @var=9; execute stmt using @var; @@ -397,7 +395,6 @@ select * from t3; a 6 7 -8 drop view v1; drop table t1,t2,t3; # Test 7-d: dependent TABLE has changed @@ -817,17 +814,14 @@ a b c 10 20 50 20 40 100 30 60 150 -# Currently a different result from conventional statements. -# A view is inlined once at prepare, later on view DDL -# 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 +# This is actually a test case for Bug#11748352 (36002 Prepared +# statements: if a view used in a statement is replaced, bad data). execute stmt; a b c -10 20 30 -20 40 60 -30 60 90 -call p_verify_reprepare_count(0); +10 20 50 +20 40 100 +30 60 150 +call p_verify_reprepare_count(1); SUCCESS flush table t2; @@ -839,9 +833,200 @@ a b c call p_verify_reprepare_count(1); 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 view t1; 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 ===================================================================== @@ -939,15 +1124,15 @@ drop view v2; create view v2 as select a from t2; execute stmt; a -1 -2 -3 +4 +5 +6 execute stmt; a -1 -2 -3 -call p_verify_reprepare_count(0); +4 +5 +6 +call p_verify_reprepare_count(1); SUCCESS flush table t1; @@ -956,7 +1141,7 @@ a 4 5 6 -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); SUCCESS execute stmt; diff --git a/mysql-test/t/ps_ddl.test b/mysql-test/t/ps_ddl.test index fb194c6b5b9..f7d14464e4e 100644 --- a/mysql-test/t/ps_ddl.test +++ b/mysql-test/t/ps_ddl.test @@ -353,23 +353,22 @@ select * from t2; drop view v1; create view v1 as select a from t2; set @var=8; ---echo # XXX: bug, the SQL statement in the trigger is still ---echo # pointing at table 't3', since the view was expanded ---echo # at first statement execution. ---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 # View in the INSERT-statement in the trigger is still pointing to +--echo # table 't3', because the trigger hasn't noticed the change +--echo # in view definition. This will be fixed by WL#4179. --echo # ---echo # Sic: the insert went into t3, even though the view now ---echo # points at t2. This is because neither the merged view ---echo # nor its prelocking list are affected by view DDL ---echo # The binary log is of course wrong, since it is not ---echo # using prepared statements +--echo # The prepared INSERT-statement however does notice the change, +--echo # but repreparation of the main statement doesn't cause repreparation +--echo # of trigger statements. --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 t3; flush table t1; @@ -736,21 +735,136 @@ drop view t1; create view t1 as select a, 2*a as b, 5*a as c from t2; select * from t1; ---echo # Currently a different result from conventional statements. ---echo # A view is inlined once at prepare, later on view DDL ---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 +--echo # This is actually a test case for Bug#11748352 (36002 Prepared +--echo # statements: if a view used in a statement is replaced, bad data). execute stmt; -call p_verify_reprepare_count(0); +call p_verify_reprepare_count(1); + 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; 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 view t1; 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 Part 18: VIEW -> VIEW (VIEW dependencies) transitions --echo ===================================================================== @@ -819,10 +933,10 @@ drop view v2; create view v2 as select a from t2; execute stmt; execute stmt; -call p_verify_reprepare_count(0); +call p_verify_reprepare_count(1); flush table t1; execute stmt; -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); execute stmt; --echo # Test 18-d: dependent TABLE has changed drop view v2; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index e0a567420ba..f464142f544 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -667,6 +667,15 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, 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()) { String buff; diff --git a/sql/table.h b/sql/table.h index 0f98f1dc0a3..dc0c0b7fc20 100644 --- a/sql/table.h +++ b/sql/table.h @@ -865,7 +865,7 @@ struct TABLE_SHARE } /** 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 new table loaded into the table definition cache (TDC). * for temporary tables it's table_map_id again. But for @@ -874,7 +874,7 @@ struct TABLE_SHARE counter incremented for every new SQL statement. Since temporary tables are thread-local, each temporary table gets a unique id. - * for everything else (views, information schema tables), + * for everything else (e.g. information schema tables), the version id is zero. This choice of version id is a large compromise @@ -889,8 +889,8 @@ struct TABLE_SHARE version id of a temporary table is never compared with a version id of a view, and vice versa. - Secondly, for base tables, we know that each DDL flushes the - respective share from the TDC. This ensures that whenever + Secondly, for base tables and views, we know that each DDL flushes + the respective share from the TDC. This ensures that whenever a table is altered or dropped and recreated, it gets a new version id. Unfortunately, since elements of the TDC are also flushed on @@ -911,26 +911,6 @@ struct TABLE_SHARE Metadata of information schema tables never changes. 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 track that a change has taken place when a view is replaced with a base table, a base table is replaced with a temporary @@ -940,7 +920,7 @@ struct TABLE_SHARE */ 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, |