Skip to content

Add gap lock based transactional statement detection for InnoDB - #26

Open
akshaysuryawanshi wants to merge 2 commits into
release-8.4.5-501from
PS-10098-gap-lock-502
Open

Add gap lock based transactional statement detection for InnoDB#26
akshaysuryawanshi wants to merge 2 commits into
release-8.4.5-501from
PS-10098-gap-lock-502

Conversation

@akshaysuryawanshi

Copy link
Copy Markdown

Adding gap lock based query detection for InnoDB. This will be useful in CI.

@akshaysuryawanshi akshaysuryawanshi self-assigned this Oct 1, 2025
@akshaysuryawanshi akshaysuryawanshi changed the title Ps 10098 gap lock 502 Add gap lock based transactional statement detection for InnoDB Oct 1, 2025
@akshaysuryawanshi

Copy link
Copy Markdown
Author

Testing,

Testing the gap lock detection functionality,

Setup,

mysql> CREATE DATABASE IF NOT EXISTS gap_test;
Query OK, 1 row affected (0.02 sec)

mysql> USE gap_test;
Database changed
mysql> DROP TABLE IF EXISTS test_innodb;
Query OK, 0 rows affected, 1 warning (0.02 sec)

mysql> CREATE TABLE test_innodb (
    ->     id INT PRIMARY KEY,
    ->     name VARCHAR(50),
    ->     age INT,
    ->     INDEX idx_age (age)
    -> ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.05 sec)

mysql> INSERT INTO test_innodb VALUES
    ->     (1, 'Alice', 25),
    ->     (5, 'Bob', 30),
    ->     (10, 'Charlie', 35),
    ->     (15, 'David', 40),
    ->     (20, 'Eve', 45);
Query OK, 5 rows affected (0.03 sec)
Records: 5  Duplicates: 0  Warnings: 0

Test 1: gap_lock_raise_error=off and innodb_detect_gap_lock_usage=off

mysql> SELECT * FROM test_innodb;
+----+---------+------+
| id | name    | age  |
+----+---------+------+
|  1 | Alice   |   25 |
|  5 | Bob     |   30 |
| 10 | Charlie |   35 |
| 15 | David   |   40 |
| 20 | Eve     |   45 |
+----+---------+------+
5 rows in set (0.01 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE;
+----+------+------+
| id | name | age  |
+----+------+------+
|  5 | Bob  |   30 |
+----+------+------+
1 row in set (0.01 sec)

mysql> SHOW WARNINGS;
Empty set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id BETWEEN 21 AND 29 FOR UPDATE;
Empty set (0.00 sec)

mysql> SHOW WARNINGS;
Empty set (0.01 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE age BETWEEN 28 AND 33 FOR UPDATE;
+----+------+------+
| id | name | age  |
+----+------+------+
|  5 | Bob  |   30 |
+----+------+------+
1 row in set (0.00 sec)

mysql> SHOW WARNINGS;
Empty set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id > 10 AND id < 20 FOR UPDATE;
+----+-------+------+
| id | name  | age  |
+----+-------+------+
| 15 | David |   40 |
+----+-------+------+
1 row in set (0.01 sec)

mysql> SHOW WARNINGS;
Empty set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id = 7 FOR UPDATE;
Empty set (0.00 sec)

mysql> SHOW WARNINGS;
Empty set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)

Test 2: gap_lock_raise_error=warning and innodb_detect_gap_lock_usage=on

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE;
+----+------+------+
| id | name | age  |
+----+------+------+
|  5 | Bob  |   30 |
+----+------+------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 8020 | Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE |
+---------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id BETWEEN 21 AND 29 FOR UPDATE;
Empty set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 8020 | Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE id BETWEEN 21 AND 29 FOR UPDATE |
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM test_innodb WHERE age BETWEEN 28 AND 33 FOR UPDATE;
+----+------+------+
| id | name | age  |
+----+------+------+
|  5 | Bob  |   30 |
+----+------+------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 8020 | Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE age BETWEEN 28 AND 33 FOR UPDATE |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id > 10 AND id < 20 FOR UPDATE;
+----+-------+------+
| id | name  | age  |
+----+-------+------+
| 15 | David |   40 |
+----+-------+------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 8020 | Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE id > 10 AND id < 20 FOR UPDATE |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id = 7 FOR UPDATE;
Empty set (0.00 sec)

mysql> SHOW WARNINGS;
Empty set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

Test 3: gap_lock_raise_error=error

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE;
ERROR 1105 (HY000): Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE
mysql> SHOW WARNINGS;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                                                                                                                                                                |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Error | 1105 | Using Gap Lock without full unique key in multi-table or multi-statement transactions is not allowed. You need to either 1: Execute 'SET SESSION gap_lock_raise_error=off' if you are sure that your application does not rely on Gap Lock. 2: Rewrite queries to use all unique key columns in WHERE equal conditions. 3: Rewrite to single-table, single-statement transaction. Query: SELECT * FROM test_innodb WHERE id BETWEEN 2 AND 8 FOR UPDATE |
| Error | 1213 | Deadlock found when trying to get lock; try restarting transaction                                                                                                                                                                                                                                                                                                                                                                                     |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)

@akshaysuryawanshi
akshaysuryawanshi force-pushed the PS-10098-gap-lock-502 branch 2 times, most recently from 1e9f49d to d3570b9 Compare October 3, 2025 20:30
- Added innodb_detect_gap_lock_usage session variable
- When enabled, InnoDB reports no gap lock support to trigger detection
- Works with gap_lock_raise_error to warn/error on gap lock usage
- Useful for CI testing and migration planning from InnoDB to RocksDB
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant