diff options
author | Konstantin Osipov <kostja@sun.com> | 2010-02-15 19:35:53 +0300 |
---|---|---|
committer | Konstantin Osipov <kostja@sun.com> | 2010-02-15 19:35:53 +0300 |
commit | 3a856d442538f1fc97bb77db9cd8b1b398d42028 (patch) | |
tree | 1b4fdfa0d7287b7d5eac1168f2c90294a9870f85 /storage/myisammrg | |
parent | c15886a111953200c6be4e67decad891ed2986dd (diff) | |
download | mariadb-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.cc | 21 |
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; |