Commit 97bd7635 authored by Sergey Vojtovich's avatar Sergey Vojtovich

BUG#32047 - 'Spurious' errors while opening MERGE tables

Accessing well defined MERGE table may return an error
stating that the merge table is incorrectly defined. This
happens if MERGE child tables were accessed before and we
failed to open another incorrectly defined MERGE table in
this connection.

myrg_open() internally used my_errno as a variable for determining
failure, and thus could be tricked into a wrong decision by other
uses of my_errno.

With this fix we use function local boolean flag instead of my_errno
to determine failure.

myisammrg/myrg_open.c:
  There are two requirement for accessing/setting my_errno variable,
  which were not followed by myrg_open():
  - it must be checked immediately after a function returned an error. There
    must be no calls to other functions that may change it's value between.
  - my_errno value must be set right before a function is going to return an
    error. There must be no calls to other functions that may change it's
    value between (that's why we have these tricks with save_errno at the
    bottom of myrg_open()).
  
  myrg_open() internally used my_errno as a variable for determining
  failure, and thus could be tricked into a wrong decision by other
  uses of my_errno.
mysql-test/r/merge.result:
  A test case for BUG#32047.
mysql-test/t/merge.test:
  A test case for BUG#32047.
parent 9a3afd1a
...@@ -40,6 +40,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -40,6 +40,7 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
IO_CACHE file; IO_CACHE file;
MI_INFO *isam=0; MI_INFO *isam=0;
uint found_merge_insert_method= 0; uint found_merge_insert_method= 0;
my_bool bad_children= FALSE;
DBUG_ENTER("myrg_open"); DBUG_ENTER("myrg_open");
LINT_INIT(key_parts); LINT_INIT(key_parts);
...@@ -89,13 +90,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -89,13 +90,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
fn_format(buff, buff, "", "", 0); fn_format(buff, buff, "", "", 0);
if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0)))) if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
{ {
my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
if (handle_locking & HA_OPEN_FOR_REPAIR) if (handle_locking & HA_OPEN_FOR_REPAIR)
{ {
myrg_print_wrong_table(buff); myrg_print_wrong_table(buff);
bad_children= TRUE;
continue; continue;
} }
goto err; goto bad_children;
} }
if (!m_info) /* First file */ if (!m_info) /* First file */
{ {
...@@ -122,13 +123,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -122,13 +123,13 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
files++; files++;
if (m_info->reclength != isam->s->base.reclength) if (m_info->reclength != isam->s->base.reclength)
{ {
my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
if (handle_locking & HA_OPEN_FOR_REPAIR) if (handle_locking & HA_OPEN_FOR_REPAIR)
{ {
myrg_print_wrong_table(buff); myrg_print_wrong_table(buff);
bad_children= TRUE;
continue; continue;
} }
goto err; goto bad_children;
} }
m_info->options|= isam->s->options; m_info->options|= isam->s->options;
m_info->records+= isam->state->records; m_info->records+= isam->state->records;
...@@ -141,8 +142,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -141,8 +142,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
m_info->tables); m_info->tables);
} }
if (my_errno == HA_ERR_WRONG_MRG_TABLE_DEF) if (bad_children)
goto err; goto bad_children;
if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO), if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO),
MYF(MY_WME | MY_ZEROFILL)))) MYF(MY_WME | MY_ZEROFILL))))
goto err; goto err;
...@@ -170,12 +171,14 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking) ...@@ -170,12 +171,14 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
pthread_mutex_unlock(&THR_LOCK_open); pthread_mutex_unlock(&THR_LOCK_open);
DBUG_RETURN(m_info); DBUG_RETURN(m_info);
bad_children:
my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
err: err:
save_errno=my_errno; save_errno=my_errno;
switch (errpos) { switch (errpos) {
case 3: case 3:
while (files) while (files)
mi_close(m_info->open_tables[--files].table); (void) mi_close(m_info->open_tables[--files].table);
my_free((char*) m_info,MYF(0)); my_free((char*) m_info,MYF(0));
/* Fall through */ /* Fall through */
case 2: case 2:
......
...@@ -940,4 +940,15 @@ m1 CREATE TABLE `m1` ( ...@@ -940,4 +940,15 @@ m1 CREATE TABLE `m1` (
`a` int(11) default NULL `a` int(11) default NULL
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1, m1; DROP TABLE t1, m1;
CREATE TABLE t1(a INT);
CREATE TABLE t2(a VARCHAR(10));
CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2);
CREATE TABLE m2(a INT) ENGINE=MERGE UNION=(t1);
SELECT * FROM t1;
a
SELECT * FROM m1;
ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
SELECT * FROM m2;
a
DROP TABLE t1, t2, m1, m2;
End of 5.0 tests End of 5.0 tests
...@@ -556,4 +556,17 @@ ALTER TABLE m1 UNION=(); ...@@ -556,4 +556,17 @@ ALTER TABLE m1 UNION=();
SHOW CREATE TABLE m1; SHOW CREATE TABLE m1;
DROP TABLE t1, m1; DROP TABLE t1, m1;
#
# BUG#32047 - 'Spurious' errors while opening MERGE tables
#
CREATE TABLE t1(a INT);
CREATE TABLE t2(a VARCHAR(10));
CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2);
CREATE TABLE m2(a INT) ENGINE=MERGE UNION=(t1);
SELECT * FROM t1;
--error ER_WRONG_MRG_TABLE
SELECT * FROM m1;
SELECT * FROM m2;
DROP TABLE t1, t2, m1, m2;
--echo End of 5.0 tests --echo End of 5.0 tests
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