Bug #24797 BlackHole engine doesn't support update, delete and drop table
Submitted: 4 Dec 2006 14:29 Modified: 8 Feb 2007 16:52
Reporter: Mikhail Petrov Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:4.1.22, 4.1.23-nightly-20061205-log OS:
Assigned to: CPU Architecture:Any
Tags: blackhole, Contribution, syntax support

[4 Dec 2006 14:29] Mikhail Petrov
Description:
I've tried to use blackhole storage engine as filter for binary logs.
I've compiled mysql from sources (mysql-4.1.22.tar.gz) with such options:
./configure --with-extra-charsets=complex --enable-thread-safe-client --enable-local-infile --disable-shared --with-charset=cp1251 --with-collation=cp1251_general_ci --with-vio --with-openssl --with-blackhole-storage-engine --prefix=/usr --without-innodb

And on updates and deletes on slave I've got these errors in error-log:
061204 15:39:03 [ERROR] Slave: Error 'Table storage engine for 'table_name' doesn't have this option' on query. Default database: ''. Query: 'update db_name.table_name set rbalance=rbalance+0.0794 where oid='41768681'', Error_code: 1031

061204 16:28:16 [ERROR] Slave: Error 'Table storage engine for 'table_name' doesn't have this option' on query. Default database: ''. Query: 'DELETE from db_name.table_name WHERE oid = '42121645'', Error_code: 1031

I tried to patch MySQL, and with a patch listed below all queries work fine.

How to repeat:
mysql> create table temp.foo (`bar` int(11)) engine=blackhole;
Query OK, 0 rows affected (0.02 sec)
mysql> update temp.foo set bar=bar+1 where bar=41768681;

Table storage engine for temp.foo doesn't have this option

Same behaviour I've got on deletes.

Suggested fix:
--- sql/ha_blackhole.cc 2006-11-03 02:16:34.000000000 +0000
+++ sql/ha_blackhole.cc      2006-12-04 13:36:44.493713731 +0000
@@ -123,6 +123,23 @@
   DBUG_RETURN(0);
 }

+int ha_blackhole::update_row(const byte * old_data, byte * new_data)
+{
+  DBUG_ENTER("ha_blackhole::update_row");
+  DBUG_RETURN(0);
+}
+
+int ha_blackhole::delete_row(const byte * buf)
+{
+  DBUG_ENTER("ha_blackhole::delete_row");
+  DBUG_RETURN(0);
+}
+
+int ha_blackhole::delete_table(const char * name)
+{
+  DBUG_ENTER("ha_blackhole::delete_table");
+  DBUG_RETURN(0);
+}

 uint ha_blackhole::lock_count(void) const
 {
--- sql/ha_blackhole.h  2006-11-03 02:17:26.000000000 +0000
+++ sql/ha_blackhole.h       2006-12-04 13:36:45.951533661 +0000
@@ -80,6 +80,9 @@
   void position(const byte *record);
   int info(uint flag);
   int external_lock(THD *thd, int lock_type);
+  int update_row(const byte * old_data, byte * new_data);
+  int delete_row(const byte * buf);
+  int delete_table(const char * name);
   uint lock_count(void) const;
   int create(const char *name, TABLE *table_arg,
              HA_CREATE_INFO *create_info);
[4 Dec 2006 16:01] MySQL Verification Team
Thank you for the bug report. Please read:
http://dev.mysql.com/doc/refman/4.1/en/blackhole-storage-engine.html

14.9. The BLACKHOLE Storage Engine

The BLACKHOLE storage engine was added in MySQL 4.1.11. This engine acts as a “black hole” that accepts data but throws it away and does not store it. Retrievals always return an empty result: .....
[4 Dec 2006 16:41] Mikhail Petrov
I've already read that part on man, and I saw such phrase:
For example, suppose that your application requires slave-side filtering rules, but transferring all binary log data to the slave first results in too much traffic. In such a case, it is possible to set up on the master host a “dummy” slave process whose default storage engine is BLACKHOLE.

But we _can't_ use BLACKHOLE for such purpose without support of UPDATEs and DELETEs. In most cases binary logs on master server consists of not only INSERTs, so I insist on it's a bug nevertheless...
[4 Dec 2006 17:04] MySQL Verification Team
Thank you for the feedback.
Sorry but is clear: "that accepts data but throws it away and does not store it"
so you can't delete or update..the very sample shows even not returns a select:

mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM test;
Empty set (0.00 sec)

so that storage engine wasn't designed for that.
[4 Dec 2006 17:39] Mikhail Petrov
Sorry, but 5.0 have support for such commands, so, I think this engine designed for such things.
I've consulted with couple of MySQL developers, and they also think so.
[4 Dec 2006 19:39] MySQL Verification Team
Thank you for the feedback. Are you able to perform the below commnds
how I did with current source server?

mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> update test set i = 5 where i =2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> delete from test where i =1;
Query OK, 0 rows affected (0.00 sec)

mysql> show create table test;
+-------+-------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                            |
+-------+-------------------------------------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `i` int(11) default NULL,
  `c` char(10) default NULL
) ENGINE=BLACKHOLE DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+-----------+
| version() |
+-----------+
| 4.1.23    |
+-----------+
1 row in set (0.00 sec)

mysql> 

Thanks in advance.
[5 Dec 2006 11:01] Mikhail Petrov
Hi, Miguel!
I've got a very strange situation.
This is what I get on 
4.1.23-nightly-20061205-log
mysql> create database test;
Query OK, 1 row affected (0.03 sec)

mysql> use test
Database changed
mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.02 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> update test set i = 5 where i =2;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> delete from test where i =1;
Query OK, 0 rows affected (0.05 sec)

mysql> show create table test;
+-------+-------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                            |
+-------+-------------------------------------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `i` int(11) default NULL,
  `c` char(10) default NULL
) ENGINE=BLACKHOLE DEFAULT CHARSET=cp1251 |
+-------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)

mysql> select version();
+-----------------------------+
| version()                   |
+-----------------------------+
| 4.1.23-nightly-20061205-log |
+-----------------------------+
1 row in set (0.01 sec)

But:

mysql> CREATE TABLE `User` (
    ->   `oid` int(11) NOT NULL default '0',
    ->   `balance` double(15,5) NOT NULL default '0.00000',
    ->   `balance_update_time` datetime NOT NULL default '0000-00-00 00:00:00',
    ->   `last_clicktime` datetime NOT NULL default '0000-00-00 00:00:00',
    ->   `rbalance` double(15,5) NOT NULL default '0.00000',
    ->   `user_load` enum('Always','Normal') NOT NULL default 'Normal',
    ->   `user_action` set('Distinct') NOT NULL default '',
    ->   `status` enum('Active','Blocked','Deleted') NOT NULL default 'Active',
    ->   `system_status` enum('Active','Blocked','Deleted') NOT NULL default 'Active',
    ->   `updated` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
    ->   `created` timestamp NOT NULL default '0000-00-00 00:00:00',
    ->   PRIMARY KEY  (`oid`),
    ->   KEY `rbalance` (`rbalance`),
    ->   KEY `created` (`created`),
    ->   KEY `status` (`status`,`system_status`)
    -> ) ENGINE=BLACKHOLE DEFAULT CHARSET=cp1251;
Query OK, 0 rows affected (0.10 sec)

mysql> update User set last_clicktime='20061205133712' where oid=32310732;
ERROR 1031 (HY000): Table storage engine for 'User' doesn't have this option
mysql> alter table User drop primary key;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> update User set last_clicktime='20061205133712' where oid=32310732;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql>

And with 4.1.22 with my patch:

mysql> use test
Database changed
mysql> CREATE TABLE test(i INT, c CHAR(10)) ENGINE = BLACKHOLE;
Query OK, 0 rows affected (0.23 sec)

mysql> INSERT INTO test VALUES(1,'record one'),(2,'record two');
Query OK, 2 rows affected (0.20 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> update test set i = 5 where i =2;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> delete from test where i =1;
Query OK, 0 rows affected (0.01 sec)

mysql> show create table test;
+-------+-------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                            |
+-------+-------------------------------------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `i` int(11) default NULL,
  `c` char(10) default NULL
) ENGINE=BLACKHOLE DEFAULT CHARSET=cp1251 |
+-------+-------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.02 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 4.1.22-log |
+------------+
1 row in set (0.10 sec)

mysql> CREATE TABLE `User` (
    ->   `oid` int(11) NOT NULL default '0',
    ->   `balance` double(15,5) NOT NULL default '0.00000',
    ->   `balance_update_time` datetime NOT NULL default '0000-00-00 00:00:00',
    ->   `last_clicktime` datetime NOT NULL default '0000-00-00 00:00:00',
    ->   `rbalance` double(15,5) NOT NULL default '0.00000',
    ->   `user_load` enum('Always','Normal') NOT NULL default 'Normal',
    ->   `user_action` set('Distinct') NOT NULL default '',
    ->   `status` enum('Active','Blocked','Deleted') NOT NULL default 'Active',
    ->   `system_status` enum('Active','Blocked','Deleted') NOT NULL default 'Active',
    ->   `updated` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
    ->   `created` timestamp NOT NULL default '0000-00-00 00:00:00',
    ->   PRIMARY KEY  (`oid`),
    ->   KEY `rbalance` (`rbalance`),
    ->   KEY `created` (`created`),
    ->   KEY `status` (`status`,`system_status`)
    -> ) ENGINE=BLACKHOLE DEFAULT CHARSET=cp1251;
Query OK, 0 rows affected (0.06 sec)

mysql> update User set last_clicktime='20061205133712' where oid=32310732;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> delete from User where oid=32310732;
Query OK, 1 row affected (0.00 sec)

mysql>

It seems to be that blackhole in nightly build doesn's support updates and deletes by indexes... But patched 4.1.22 supports all these operations...
[5 Dec 2006 13:20] Sergei Golubchik
Something's fishy is going on here. There shouldn't be any need for update_row/delete_row in ha_blackhole, because if the table has no rows, there's nothing to delete/update and delete/update methods should never be called.
[5 Dec 2006 13:32] Mikhail Petrov
Sergei, I completely understand purposes of blackhole, and I think that current version of that engine don't let me use that for filtering, for example.

As I wrote in previous comment, blackhole can't work with updates and deletes using primary keys. Yes, we have workaround - create table without primary keys will help, but in such case we can hit errors with altering tables.
[5 Dec 2006 14:41] Sergei Golubchik
I wan't speaking about the purpose. I was saying that update_row/delete_row of ha_blackhole should never be called, so it doesn't matter what they return. If they are called - as in your case - it's a bug.
But the bug is that they're called, not that they're not implemented.
[5 Dec 2006 14:45] Mikhail Petrov
Oh, thanks, I've understood :)
By the way, I've deleted OS - I think it affects all operating systems...
[8 Feb 2007 16:51] Sergei Golubchik
A duplicate of BUG#19717
[11 Feb 2007 6:09] gehaijiang gehaijiang
Please resolve this problem! 

There is a bug on blackhole engine.

See:
UPDATE Query Error on BLACKHOLE when using WHERE on column with UNIQUE OR PRIMARY INDEX