Bug #16229 MySQL/InnoDB uses full explicit table locks in trigger processing
Submitted: 5 Jan 2006 16:57 Modified: 2 Feb 2006 18:53
Reporter: Heikki Tuuri
Status: Closed
Category:Server: InnoDB Severity:S3 (Non-critical)
Version:5.0 OS:Any (All)
Assigned to: Bugs System Target Version:

[5 Jan 2006 16:57] Heikki Tuuri
Description:
Hi!

This was noted in the Forums:

http://forums.mysql.com/read.php?22,59979

A trigger requests an X-lock on the table, and ha_innobase::store_lock() does not weaken
it, probably because MySQL has set:

thd->in_lock_tables == TRUE

and

thd->lex->sql_command != SQLCOM_CALL.

That can cause a lot of deadlocks and reduced concurrency.

Regards,

Heikki

How to repeat:
See above.

Suggested fix:
We should check what SQLCOM_... code corresponds to an explicit LOCK TABLES command by
the user, and in all the other cases weaken lock_type not to take a full table lock.
[6 Jan 2006 16:22] Valeriy Kravchuk
Thank you for a problem report. Can you, please, provide a simple test case, because I had
not found a trigger definition on that forum thread.
[7 Jan 2006 2:13] Heikki Tuuri
Valeriy,

I guess any trigger that modifies the table we are inserting into will serve as an
example. InnoDB currently only weakens the locks in the SQLCOM_CALL case. But in trigger
execution I guess it is SQLCOM_INSERT or similar.

Regards,

Heikki
[9 Jan 2006 11:52] Heikki Tuuri
Assigning this to Jan. Please check what SQLCOM_... code corresponds to an explicit LOCK
TABLES command by the user. In other cases, weaken the lock like we do in the SQLCOM_CALL
case (a stored procedure call).
[9 Jan 2006 12:12] Jan Lindström
Tested using 5.0.18 and query LOCK TABLES t1 READ. In this case thd->lex->sql_command == 
SQLCOM_LOCK_TABLES.
[9 Jan 2006 14:32] Jan Lindström
Verified using gdb (set a breakpoint to ha_innobase::external_lock) and using MySQL 5.0.18
with following test case:

CREATE TABLE t1 (id int NOT NULL, b int, PRIMARY KEY  (id)) ENGINE=InnoDB;
delimiter |
create trigger t1t after insert on t1 for each row begin update t1 set NEW.b = 5; end |
delimiter ;
insert into t1(id) values (111),(121),(131);

Here is gdb output:

Breakpoint 1, ha_innobase::external_lock (this=0x8cab360, thd=0x8c77788, lock_type=1) at
ha_innodb.cc:6338

6338                    if (prebuilt->select_lock_type != LOCK_NONE) {
(gdb)
6340                            if (thd->in_lock_tables &&
(gdb)
6347                                                            NULL, 0);
(gdb) list 6346
6341                                thd->lex->sql_command != SQLCOM_CALL &&
6342                                thd->variables.innodb_table_locks &&
6343                                (thd->options & OPTION_NOT_AUTOCOMMIT)) {
6344
6345                                    ulint   error;
6346                                    error = row_lock_table_for_mysql(prebuilt,
6347                                                            NULL, 0);
6348
6349                                    if (error != DB_SUCCESS) {
6350                                            error = convert_error_code_to_mysql(
(gdb) p thd->in_lock_tables
$3 = true
(gdb) p thd->lex->sql_command
$4 = SQLCOM_INSERT
[31 Jan 2006 19:53] Alexander Ivanov
Fixed in 5.0.19.
Patch: http://lists.mysql.com/commits/1958.
[2 Feb 2006 18:53] Mike Hillyer
Documented in 5.0.19 changelog:

     <listitem>
        <para>
          InnoDB used full explicit table locks
          in trigger processing. (Bug #16229)
        </para>
      </listitem>
[24 May 2006 14:23] Dmitri Lenev
Bug #13893 was marked as duplicate of this bug.