summaryrefslogtreecommitdiff
path: root/storage/myisammrg
diff options
context:
space:
mode:
authorKonstantin Osipov <kostja@sun.com>2010-02-15 19:35:53 +0300
committerKonstantin Osipov <kostja@sun.com>2010-02-15 19:35:53 +0300
commit3a856d442538f1fc97bb77db9cd8b1b398d42028 (patch)
tree1b4fdfa0d7287b7d5eac1168f2c90294a9870f85 /storage/myisammrg
parentc15886a111953200c6be4e67decad891ed2986dd (diff)
downloadmariadb-git-3a856d442538f1fc97bb77db9cd8b1b398d42028.tar.gz
A fix and a test case for Bug#47648 "main.merge fails sporadically".
If a prepared statement used both a MyISAMMRG table and a stored function or trigger, execution could fail with "No such table" error or crash. The error would come from a failure of the MyISAMMRG engine to meet the expectations of the prelocking algorithm, in particular maintain lex->query_tables_own_last pointer in sync with lex->query_tables_last pointer/the contents of lex->query_tables. When adding merge children, the merge engine would extend the table list. Then, when adding prelocked tables, the prelocking algorithm would use a pointer to the last merge child to assign to lex->query_tables_own_last. Then, when merge children were removed at the end of open_tables(), lex->query_tables_own_last was not updated, and kept pointing to a removed merge child. The fix ensures that query_tables_own_last is always in sync with lex->query_tables_last. This is a regression introduced by WL#4144 and present only in next-4284 tree and 6.0. mysql-test/r/merge.result: Update results (Bug#47648). mysql-test/t/merge.test: Add a test case for Bug#47648. Update the result file to reflect a fix of another bug in MyISAMMRG code: not maintaining lex->query_tables_own_last allowed a stored function or trigger to modify a merge table which was already updated by the main statement. It is not allowed for other storage engines, and should not be allowed for MyISAMMRG. storage/myisammrg/ha_myisammrg.cc: When adding children to the list of tables to open, make sure that we properly set lex->query_tables_own_last. When removing the children, update lex->query_tables_own_last if necessary.
Diffstat (limited to 'storage/myisammrg')
-rw-r--r--storage/myisammrg/ha_myisammrg.cc21
1 files changed, 21 insertions, 0 deletions
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index 60de6d361e5..066290ab515 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -458,6 +458,18 @@ int ha_myisammrg::add_children_list(void)
*/
if (thd->lex->query_tables_last == &parent_l->next_global)
thd->lex->query_tables_last= this->children_last_l;
+ /*
+ The branch below works only when re-executing a prepared
+ statement or a stored routine statement:
+ We've just modified query_tables_last. Keep it in sync with
+ query_tables_last_own, if it was set by the prelocking code.
+ This ensures that the check that prohibits double updates (*)
+ can correctly identify what tables belong to the main statement.
+ (*) A double update is, e.g. when a user issues UPDATE t1 and
+ t1 has an AFTER UPDATE trigger that also modifies t1.
+ */
+ if (thd->lex->query_tables_own_last == &parent_l->next_global)
+ thd->lex->query_tables_own_last= this->children_last_l;
end:
DBUG_RETURN(0);
@@ -888,6 +900,15 @@ int ha_myisammrg::detach_children(void)
if (thd->lex->query_tables_last == this->children_last_l)
thd->lex->query_tables_last= this->children_l->prev_global;
+ /*
+ If the statement requires prelocking, and prelocked
+ tables were added right after merge children, modify the
+ last own table pointer to point at prev_global of the merge
+ parent.
+ */
+ if (thd->lex->query_tables_own_last == this->children_last_l)
+ thd->lex->query_tables_own_last= this->children_l->prev_global;
+
/* Terminate child list. So it cannot be tried to remove again. */
*this->children_last_l= NULL;
this->children_l->prev_global= NULL;