Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-18044

select (consistent read) within IF block in store procedure locks rows

Details

    • Bug
    • Status: Confirmed (View Workflow)
    • Major
    • Resolution: Unresolved
    • 5.5(EOL), 10.0(EOL), 10.1(EOL), 10.2(EOL), 10.3(EOL), 10.4(EOL), 10.5
    • 10.5
    • Red Hat Enterprise Linux Server release 7.4

    Description

      I have a problem with SELECT in stored procedure.

      Isolation level is READ-COMMITED, engine is InnoDB so all select should be nonlocking consistent read: https://dev.mysql.com/doc/refman/8.0/en/innodb-consistent-read.html

      Following select in store procedure locks acquires lock on table agent:

      IF  v_pack_agent_id IS NULL OR 
          v_pack_agent_id not in                  
          (
              select ID from agent where LINKED_AGENTS_GUID = (select LINKED_AGENTS_GUID from agent where ID = a_agent_id) union all 
              select a_agent_id
          )
      THEN
          SET a_sign = SIGN_NOT_OWN_BLOCK;
          LEAVE l_proc;
      END IF;
      

      Table agent definition:

      MariaDB [db_mercury]> show create table agent\G
      *************************** 1. row ***************************
      Table: agent
      Create Table: CREATE TABLE `agent` (
      `ID` smallint(5) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PK',
       ...
      `LINKED_AGENTS_GUID` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
       PRIMARY KEY (`ID`),
       UNIQUE KEY `UK$ORA_ID` (`ORA_ID`),
       KEY `IDX_LINKED_AGENTS_GUID` (`LINKED_AGENTS_GUID`)
       ) ENGINE=InnoDB AUTO_INCREMENT=6198 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
      

      Problem is because select nested in IF block, if I move select outside of IF like below, then no locks are acquired. This locks nothing:

      select ID from agent where LINKED_AGENTS_GUID = (select LINKED_AGENTS_GUID from agent where ID = a_agent_id) union all 
      select a_agent_id
      

      For me it seems like a bug.

      Attachments

        Issue Links

          Activity

            What kind of table lock do you observe, and where do you see it?

            elenst Elena Stepanova added a comment - What kind of table lock do you observe, and where do you see it?
            pustovalov1 Dmitry Pustovalov added a comment - - edited

            I observe shared lock on agent table.
            I attach minimal reproducible example for my issue, sql-script creating database with one table, few rows and stored procedure.
            After applying script it's easy to reproduce problem:

            SESSION 1.

            MariaDB [lock_test_db]> set autocommit 0;
            Query OK, 0 rows affected (0.00 sec)
             
            MariaDB [lock_test_db]> call lock_test(1, 1);
            +---+
            | 1 |
            +---+
            | 1 |
            +---+
            1 row in set (0.00 sec)
             
            Query OK, 0 rows affected (0.00 sec)
            

            SESSION 2.

            MariaDB [lock_test_db]> set autocommit 0;
            Query OK, 0 rows affected (0.00 sec)
             
            MariaDB [lock_test_db]> select * from agent where id = 1 lock in share mode;
            +----+------------+
            | id | agent_guid |
            +----+------------+
            |  1 | guid 1     |
            +----+------------+
            1 row in set (0.02 sec)
             
            MariaDB [lock_test_db]> update agent set agent_guid = 'new guid' where id = 1 ;
            ^CCtrl-C -- query killed. Continuing normally.
            ERROR 1317 (70100): Query execution was interrupted
            MariaDB [lock_test_db]> Ctrl-C -- exit!
            
            

            As you can see in session 2 I can acquire S-lock on row with id = 1, but I can't acquire X lock.

            Some innodb diagnostics:

            1. innodb status

            show engine innodb status
             
            ---TRANSACTION 3142821, ACTIVE 350 sec
            2 lock struct(s), heap size 360, 1 row lock(s)
            MySQL thread id 41, OS thread handle 0x7fe94be31b00, query id 2883 localhost root init
            

            2. INNODB_TRX

            MariaDB [lock_test_db]> select * from information_schema.INNODB_TRX where trx_id = 3142821\G
            *************************** 1. row ***************************
                                trx_id: 3142821
                             trx_state: RUNNING
                           trx_started: 2019-01-02 01:43:25
                 trx_requested_lock_id: NULL
                      trx_wait_started: NULL
                            trx_weight: 2
                   trx_mysql_thread_id: 41
                             trx_query: NULL
                   trx_operation_state: NULL
                     trx_tables_in_use: 0
                     trx_tables_locked: 0
                      trx_lock_structs: 2
                 trx_lock_memory_bytes: 360
                       trx_rows_locked: 1
                     trx_rows_modified: 0
               trx_concurrency_tickets: 0
                   trx_isolation_level: READ COMMITTED
                     trx_unique_checks: 1
                trx_foreign_key_checks: 1
            trx_last_foreign_key_error: NULL
             trx_adaptive_hash_latched: 0
             trx_adaptive_hash_timeout: 10000
                      trx_is_read_only: 0
            trx_autocommit_non_locking: 0
            1 row in set (0.00 sec)
            

            3. Table INNODB_LOCKS is empty (why?)

            pustovalov1 Dmitry Pustovalov added a comment - - edited I observe shared lock on agent table. I attach minimal reproducible example for my issue, sql-script creating database with one table, few rows and stored procedure. After applying script it's easy to reproduce problem: SESSION 1. MariaDB [lock_test_db]> set autocommit 0 ; Query OK, 0 rows affected ( 0.00 sec)   MariaDB [lock_test_db]> call lock_test( 1 , 1 ); +---+ | 1 | +---+ | 1 | +---+ 1 row in set ( 0.00 sec)   Query OK, 0 rows affected ( 0.00 sec) SESSION 2. MariaDB [lock_test_db]> set autocommit 0; Query OK, 0 rows affected (0.00 sec)   MariaDB [lock_test_db]> select * from agent where id = 1 lock in share mode; + ----+------------+ | id | agent_guid | + ----+------------+ | 1 | guid 1 | + ----+------------+ 1 row in set (0.02 sec)   MariaDB [lock_test_db]> update agent set agent_guid = 'new guid' where id = 1 ; ^CCtrl-C -- query killed. Continuing normally. ERROR 1317 (70100): Query execution was interrupted MariaDB [lock_test_db]> Ctrl-C -- exit! As you can see in session 2 I can acquire S-lock on row with id = 1, but I can't acquire X lock. Some innodb diagnostics: 1. innodb status show engine innodb status   ---TRANSACTION 3142821 , ACTIVE 350 sec 2 lock struct(s), heap size 360 , 1 row lock(s) MySQL thread id 41 , OS thread handle 0x7fe94be31b00 , query id 2883 localhost root init 2. INNODB_TRX MariaDB [lock_test_db]> select * from information_schema.INNODB_TRX where trx_id = 3142821 \G *************************** 1 . row *************************** trx_id: 3142821 trx_state: RUNNING trx_started: 2019 - 01 - 02 01 : 43 : 25 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 2 trx_mysql_thread_id: 41 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 0 trx_lock_structs: 2 trx_lock_memory_bytes: 360 trx_rows_locked: 1 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: READ COMMITTED trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 1 row in set ( 0.00 sec) 3. Table INNODB_LOCKS is empty (why?)

            Thanks for the clarification and test case.
            Indeed, there is a difference in behavior for which I have no logical (or illogical, but documented) explanation.

            Below is an MTR-friendly demonstration of the difference in locking, based on the provided test case.
            The first procedure pr1() doesn't leave any locks behind, as shown by ENGINE INNODB STATUS and can be further verified by running an UPDATE on the row with id=1.
            The second procedure pr2(), which is almost identical except that it runs SELECT from inside an IF condition, leaves a lock behind.

            Transactions look different in different versions, but the effect can be observed on all MariaDB and MySQL versions.

            Both REPEATABLE READ and READ COMMITTED exhibit the same behavior, the output is for READ COMMITTED.

            --source include/have_innodb.inc
             
            CREATE TABLE t1 (
              id INT NOT NULL AUTO_INCREMENT,
              f varchar(64) DEFAULT NULL,
              PRIMARY KEY (id)
            ) ENGINE=InnoDB;
             
            INSERT INTO t1 VALUES (1, 'guid 1');
            INSERT INTO t1 VALUES (2, 'guid 1');
            INSERT INTO t1 VALUES (3, 'guid 2');
             
            --delimiter $$
             
            CREATE PROCEDURE pr1()
            BEGIN
              SELECT 1 IN ( SELECT id FROM t1 WHERE f = 'guid 1' );
              SELECT 2;
            END$$
             
            CREATE PROCEDURE pr2()
            BEGIN
              IF
                1 IN ( SELECT id FROM t1 WHERE f = 'guid 1' )
              THEN
                SELECT 2;
              END IF;
            END $$
             
            --delimiter ;
             
            --connect (con1,localhost,root,,)
            SET autocommit= 0;
            CALL pr1();
             
            --connection default
            show engine innodb status;
             
            --connection con1
            COMMIT;
            CALL pr2();
             
            --connection default
            show engine innodb status;
            

            10.3

            after pr1

            ------------
            TRANSACTIONS
            ------------
            Trx id counter 42
            Purge done for trx's n:o < 42 undo n:o < 0 state: running
            History list length 19
            Total number of lock structs in row lock hash table 0
            LIST OF TRANSACTIONS FOR EACH SESSION:
            ---TRANSACTION 421115617190128, not started
            0 lock struct(s), heap size 1160, 0 row lock(s)
            

            after pr2

            ------------
            TRANSACTIONS
            ------------
            Trx id counter 42
            Purge done for trx's n:o < 42 undo n:o < 0 state: running but idle
            History list length 19
            Total number of lock structs in row lock hash table 1
            LIST OF TRANSACTIONS FOR EACH SESSION:
            ---TRANSACTION 421115617190128, not started
            0 lock struct(s), heap size 1160, 0 row lock(s)
            

            10.1 (with XtraDB)

            after pr1

            ------------
            TRANSACTIONS
            ------------
            Trx id counter 1287
            Purge done for trx's n:o < 789 undo n:o < 0 state: running but idle
            History list length 6
            Total number of lock structs in row lock hash table 0
            LIST OF TRANSACTIONS FOR EACH SESSION:
            ---TRANSACTION 1285, not started
            MySQL thread id 3, OS thread handle 0x7f3d9eee2b00, query id 29 localhost root init
            show engine innodb status
            ---TRANSACTION 1286, ACTIVE 0 sec
            MySQL thread id 4, OS thread handle 0x7f3d9ee98b00, query id 26 localhost root 
            Trx #rec lock waits 0 #table lock waits 0
            Trx total rec lock wait time 0 SEC
            Trx total table lock wait time 0 SEC
            

            after pr2

            ------------
            TRANSACTIONS
            ------------
            Trx id counter 1288
            Purge done for trx's n:o < 789 undo n:o < 0 state: running but idle
            History list length 6
            Total number of lock structs in row lock hash table 1
            LIST OF TRANSACTIONS FOR EACH SESSION:
            ---TRANSACTION 1285, not started
            MySQL thread id 3, OS thread handle 0x7f3d9eee2b00, query id 34 localhost root init
            show engine innodb status
            ---TRANSACTION 1287, ACTIVE 0 sec
            2 lock struct(s), heap size 376, 1 row lock(s)
            MySQL thread id 4, OS thread handle 0x7f3d9ee98b00, query id 31 localhost root 
            Trx #rec lock waits 0 #table lock waits 0
            Trx total rec lock wait time 0 SEC
            Trx total table lock wait time 0 SEC
            

            elenst Elena Stepanova added a comment - Thanks for the clarification and test case. Indeed, there is a difference in behavior for which I have no logical (or illogical, but documented) explanation. Below is an MTR-friendly demonstration of the difference in locking, based on the provided test case. The first procedure pr1() doesn't leave any locks behind, as shown by ENGINE INNODB STATUS and can be further verified by running an UPDATE on the row with id=1. The second procedure pr2() , which is almost identical except that it runs SELECT from inside an IF condition, leaves a lock behind. Transactions look different in different versions, but the effect can be observed on all MariaDB and MySQL versions. Both REPEATABLE READ and READ COMMITTED exhibit the same behavior, the output is for READ COMMITTED. --source include/have_innodb.inc   CREATE TABLE t1 ( id INT NOT NULL AUTO_INCREMENT, f varchar (64) DEFAULT NULL , PRIMARY KEY (id) ) ENGINE=InnoDB;   INSERT INTO t1 VALUES (1, 'guid 1' ); INSERT INTO t1 VALUES (2, 'guid 1' ); INSERT INTO t1 VALUES (3, 'guid 2' );   --delimiter $$   CREATE PROCEDURE pr1() BEGIN SELECT 1 IN ( SELECT id FROM t1 WHERE f = 'guid 1' ); SELECT 2; END $$   CREATE PROCEDURE pr2() BEGIN IF 1 IN ( SELECT id FROM t1 WHERE f = 'guid 1' ) THEN SELECT 2; END IF ; END $$   --delimiter ;   --connect (con1,localhost,root,,) SET autocommit= 0; CALL pr1();   --connection default show engine innodb status;   --connection con1 COMMIT ; CALL pr2();   --connection default show engine innodb status; 10.3 after pr1 ------------ TRANSACTIONS ------------ Trx id counter 42 Purge done for trx's n:o < 42 undo n:o < 0 state: running History list length 19 Total number of lock structs in row lock hash table 0 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421115617190128, not started 0 lock struct(s), heap size 1160, 0 row lock(s) after pr2 ------------ TRANSACTIONS ------------ Trx id counter 42 Purge done for trx's n:o < 42 undo n:o < 0 state: running but idle History list length 19 Total number of lock structs in row lock hash table 1 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 421115617190128, not started 0 lock struct(s), heap size 1160, 0 row lock(s) 10.1 (with XtraDB) after pr1 ------------ TRANSACTIONS ------------ Trx id counter 1287 Purge done for trx's n:o < 789 undo n:o < 0 state: running but idle History list length 6 Total number of lock structs in row lock hash table 0 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 1285, not started MySQL thread id 3, OS thread handle 0x7f3d9eee2b00, query id 29 localhost root init show engine innodb status ---TRANSACTION 1286, ACTIVE 0 sec MySQL thread id 4, OS thread handle 0x7f3d9ee98b00, query id 26 localhost root Trx #rec lock waits 0 #table lock waits 0 Trx total rec lock wait time 0 SEC Trx total table lock wait time 0 SEC after pr2 ------------ TRANSACTIONS ------------ Trx id counter 1288 Purge done for trx's n:o < 789 undo n:o < 0 state: running but idle History list length 6 Total number of lock structs in row lock hash table 1 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 1285, not started MySQL thread id 3, OS thread handle 0x7f3d9eee2b00, query id 34 localhost root init show engine innodb status ---TRANSACTION 1287, ACTIVE 0 sec 2 lock struct(s), heap size 376, 1 row lock(s) MySQL thread id 4, OS thread handle 0x7f3d9ee98b00, query id 31 localhost root Trx #rec lock waits 0 #table lock waits 0 Trx total rec lock wait time 0 SEC Trx total table lock wait time 0 SEC

            I believe that this needs some fix in ha_innobase::store_lock() or ha_innobase::external_lock() or the callers of these functions.

            marko Marko Mäkelä added a comment - I believe that this needs some fix in ha_innobase::store_lock() or ha_innobase::external_lock() or the callers of these functions.

            People

              sanja Oleksandr Byelkin
              pustovalov1 Dmitry Pustovalov
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.