summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Babaev <igor@askmonty.org>2011-06-09 00:13:00 -0700
committerIgor Babaev <igor@askmonty.org>2011-06-09 00:13:00 -0700
commit7f345153f91c5395e5ab4ce5906fcabbb6d06f51 (patch)
tree00d8d3897c98f18bad884c69195cef98e8739105
parentdb0c3406011d9a6d6fdb98c1c1f7925d243bd1f9 (diff)
downloadmariadb-git-7f345153f91c5395e5ab4ce5906fcabbb6d06f51.tar.gz
Fixed LP bug #794038.
INSERT/UPDATE/DELETE statement that used a temptable view v1 could lead to a crash if v1 was defined as a select from a mergeable view v2 that selected rows from a temptable view v3. When INSERT/UPDATE/DELETE uses a view that is not updatable then field translation for the view should be created before the prepare phase.
-rw-r--r--mysql-test/r/view.result16
-rw-r--r--mysql-test/t/view.test20
-rw-r--r--sql/sql_derived.cc15
-rw-r--r--sql/sql_parse.cc3
4 files changed, 43 insertions, 11 deletions
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 4eaf1eb4793..9f720019303 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -4168,3 +4168,19 @@ a a b
2 2 30
DROP VIEW v2;
DROP TABLE t1,t2;
+#
+# Bug#794038: crash with INSERT/UPDATE/DELETE
+# over a non-updatable view
+#
+CREATE TABLE t1 (a int);
+CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1;
+CREATE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM v1;
+CREATE ALGORITHM = TEMPTABLE VIEW v3 AS SELECT * FROM v2;
+INSERT INTO v3 VALUES (1);
+ERROR HY000: The target table v3 of the INSERT is not insertable-into
+UPDATE v3 SET a=0;
+ERROR HY000: The target table v3 of the UPDATE is not updatable
+DELETE FROM v3;
+ERROR HY000: The target table v3 of the DELETE is not updatable
+DROP VIEW v1,v2,v3;
+DROP TABLE t1;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index b2032d5d6ba..626cc506e78 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -4114,3 +4114,23 @@ SELECT * FROM t1,v2
DROP VIEW v2;
DROP TABLE t1,t2;
+
+--echo #
+--echo # Bug#794038: crash with INSERT/UPDATE/DELETE
+--echo # over a non-updatable view
+--echo #
+
+CREATE TABLE t1 (a int);
+CREATE ALGORITHM = TEMPTABLE VIEW v1 AS SELECT * FROM t1;
+CREATE ALGORITHM = MERGE VIEW v2 AS SELECT * FROM v1;
+CREATE ALGORITHM = TEMPTABLE VIEW v3 AS SELECT * FROM v2;
+
+-- error ER_NON_INSERTABLE_TABLE
+INSERT INTO v3 VALUES (1);
+-- error ER_NON_UPDATABLE_TABLE
+UPDATE v3 SET a=0;
+-- error ER_NON_UPDATABLE_TABLE
+DELETE FROM v3;
+
+DROP VIEW v1,v2,v3;
+DROP TABLE t1;
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index ca56f0fa0a6..9bfa49c5f2d 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -467,6 +467,12 @@ bool mysql_derived_merge_for_insert(THD *thd, LEX *lex, TABLE_LIST *derived)
if (derived->merged_for_insert)
return FALSE;
+ /* It's a target view for an INSERT, create field translation only. */
+ if (!derived->updatable || derived->is_materialized_derived())
+ {
+ bool res= derived->create_field_translation(thd);
+ return res;
+ }
if (!derived->is_multitable())
{
TABLE_LIST *tl=((TABLE_LIST*)dt_select->table_list.first);
@@ -603,16 +609,9 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *derived)
bool res= FALSE;
// Skip already prepared views/DT
- if (!unit || unit->prepared)
+ if (!unit || unit->prepared || derived->merged_for_insert)
DBUG_RETURN(FALSE);
- /* It's a target view for an INSERT, create field translation only. */
- if (derived->merged_for_insert)
- {
- res= derived->create_field_translation(thd);
- DBUG_RETURN(res);
- }
-
Query_arena *arena= thd->stmt_arena, backup;
if (arena->is_conventional())
arena= 0; // For easier test
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f891d307e9b..165a898910d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2697,9 +2697,6 @@ mysql_execute_command(THD *thd)
}
}
}
- if (mysql_handle_single_derived(thd->lex, create_table,
- DT_MERGE_FOR_INSERT))
- DBUG_RETURN(1);
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.options & HA_LEX_CREATE_TMP_TABLE)