Bug #38055 falcon bug 30210 reproduces in archive storage engine
Submitted: 11 Jul 2008 18:43 Modified: 7 Oct 2008 9:46
Reporter: Zardosht Kasheff (OCA) Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Archive storage engine Severity:S2 (Serious)
Version:5.1.23-rc, 4.1, 5.0, 5.1, 6.0 bzr OS:Any
Assigned to: CPU Architecture:Any
Tags: get_share

[11 Jul 2008 18:43] Zardosht Kasheff
Description:
It seems that falcon bug 30210 also exists in the falcon storage engine. Looking at bug 30210, I could not tell what the problem and fix is, so perhaps this is the same issue as bug 30210.

Looking at the code, it seems that the function get_share does not act correctly. In get_share, either my_hash_insert or hash_search does not act properly.

Here is what seems to be happening in ha_archive::get_share. I do a create table t. That creates an instance of a ARCHIVE_SHARE and calls my_hash_insert. At this point, an ARCHIVE_SHARE object exists for the table t, but not for T. Then I do create table T. What happens for table T is that instead of hash_search returning NULL, hash_search returns an instance of the ARCHIVE_SHARE associated with table t. This is wrong. One can verify this is happening by noticing that at the end of this get_share call, the value of share->use_count is 2.

I think the reason one sees this erroneous behavior is that the ARCHIVE_SHARE object holds pointers to classes that actually store the data.

This bug with XXX_SHARE objects seems to exist in InnoDB as well. If one performs the same steps, one will see that the value of share->use_count is 2 after the call for the second table. It seems that the reason InnoDB does not show this wrong behavior is that the share object for InnoDB holds much less information than the share object for Archive.

How to repeat:
Perform the following test:

let $engine = 'archive';
eval SET @@storage_engine = $engine;

--disable_warnings
DROP TABLE IF EXISTS T;
DROP TABLE IF EXISTS t;
--enable_warnings

CREATE TABLE T (a int);

# ----------------------------------------------------- #
# --- Test                                          --- #
# ----------------------------------------------------- #
#--error ER_TABLE_EXISTS_ERROR, ER_CANT_CREATE_TABLE
CREATE TABLE t (a int);
INSERT INTO T VALUES (1);
insert into t values(2);
# ----------------------------------------------------- #
# --- Check                                         --- #
# ----------------------------------------------------- #
SELECT * FROM T;
select count(*) from T;
SELECT * FROM t;
select count(*) FROM t;
# ----------------------------------------------------- #
# --- Final cleanup                                 --- #
# ----------------------------------------------------- #
--disable_warnings
DROP TABLE IF EXISTS t;
DROP TABLE IF EXISTS T;
--enable_warnings

Notice that each table has elements (1) and (2) in them.

Suggested fix:
The second hash_search as described in the Description should not return the share object associated with the other table. It should return NULL and a new share object should be allocated.
[11 Jul 2008 18:53] Sveta Smirnova
Thank you for the report.

Verified as described.
[14 Jul 2008 10:06] Sergei Golubchik
this ::get_share() technique was first used in BDB and other handlers copied it.

In 6.0 we've introduced a better and simpler method - in TABLE_SHARE there's a void *ha_data pointer where you can store anything you want (practically - a pointer to your share). No hash lookups or name mapping anymore, MySQL does it for you and gives you a pointer which is always different for two distinct tables and always the same for all handlers that correspond to the same table.
[7 Oct 2008 9:46] Mattias Jonsson
Duplicate of bug#37719, that proposed patch fixes this bug.