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

Inconsistent behaviors of UPDATE under RU & RC isolation level

Details

    Description

      Isolation Level: Read Uncommitted & Read Committed.
      The behaviors of UPDATE for different rows are inconsistent. Just some of the rows are not updated while others are.

      /* init */ drop table if exists t;
      /* init */ create table t(a int, b int);
      /* init */ insert into t values(null, 1), (2, 2), (null, null), (null, 3), (4, null);
       
      /* s1 */ begin;
      /* s1 */ update t set a = 10 where 1;
      /* s2 */ begin;
      /* s2 */ update t set b = 20 where a; -- blocked
      /* s1 */ commit; -- s2 unblocked
      /* s2 */ commit;
       
      select * from t;
       
      +------+------+
      | a    | b    |
      +------+------+
      |   10 |    1 |
      |   10 |   20 |
      |   10 |   20 |
      |   10 |   20 |
      |   10 |   20 |
      +------+------+
      

      The field b of the first row is not updated but other rows are updated.

      After several attempts, I found that the results depend on the distribution of the data in the table rather than the timing.

      If the initial table is like:

      +------+------+
      | a    | b    |
      +------+------+
      |    1 |    1 |
      |    2 |    2 |
      | null | null |
      | null |    3 |
      |    4 | null |
      +------+------+
      

      then, the result will be

      +------+------+
      | a    | b    |
      +------+------+
      |   10 |   20 |
      |   10 |   20 |
      |   10 |   20 |
      |   10 |   20 |
      |   10 |   20 |
      +------+------+
      

      More specifically, if there exists a row whose column `a` is not NULL, and it is the first record from top to bottom whose column `a` is not NULL. Then, all rows before it with a NULL column `a` will not be updated, while all rows after it with a NULL column `a` will be updated. This means that even the execution of a single statement is not atomic.

      This bug can be reproduced under Read Uncommitted and Read Committed.

      Attachments

        Issue Links

          Activity

            dinary dinary created issue -
            dinary dinary made changes -
            Field Original Value New Value
            Description Isolation Level: Read Uncommitted.
            The behaviors of UPDATE for different rows are inconsistent. Just some of the rows are not updated while others are.


            {code:sql}
            /* init */ drop table if exists t;
            /* init */ create table t(a int, b int);
            /* init */ insert into t values(null, 1), (2, 2), (null, null), (null, 3), (4, null);

            /* s1 */ begin;
            /* s1 */ update t set a = 10 where 1;
            /* s2 */ begin;
            /* s2 */ update t set b = 20 where a; -- blocked
            /* s1 */ commit; -- s2 unblocked
            /* s2 */ commit;

            select * from t;

            +------+------+
            | a | b |
            +------+------+
            | 10 | 1 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}

            The field b of the first row is not updated but other rows are updated.

            After several attempts, I found that the results depend on the distribution of the data in the table rather than the timing.

            If the initial table is like:
            +------+------+
            | a | b |
            +------+------+
            | 1 | 1 |
            | 2 | 2 |
            | null | null |
            | null | 3 |
            | 4 | null |
            +------+------+
            then, the result will be
            +------+------+
            | a | b |
            +------+------+
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+

            More specifically, if there exists a row whose column `a` is not NULL, and it is the first record from top to bottom whose column `a` is not NULL. Then, all rows before it with a NULL column `a` will not be updated, while all rows after it with a NULL column `a` will be updated. This means that even the execution of a single statement is not atomic.
            Isolation Level: Read Uncommitted.
            The behaviors of UPDATE for different rows are inconsistent. Just some of the rows are not updated while others are.


            {code:sql}
            /* init */ drop table if exists t;
            /* init */ create table t(a int, b int);
            /* init */ insert into t values(null, 1), (2, 2), (null, null), (null, 3), (4, null);

            /* s1 */ begin;
            /* s1 */ update t set a = 10 where 1;
            /* s2 */ begin;
            /* s2 */ update t set b = 20 where a; -- blocked
            /* s1 */ commit; -- s2 unblocked
            /* s2 */ commit;

            select * from t;

            +------+------+
            | a | b |
            +------+------+
            | 10 | 1 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}

            The field b of the first row is not updated but other rows are updated.

            After several attempts, I found that the results depend on the distribution of the data in the table rather than the timing.

            If the initial table is like:

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 1 | 1 |
            | 2 | 2 |
            | null | null |
            | null | 3 |
            | 4 | null |
            +------+------+
            {code}

            then, the result will be

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}


            More specifically, if there exists a row whose column `a` is not NULL, and it is the first record from top to bottom whose column `a` is not NULL. Then, all rows before it with a NULL column `a` will not be updated, while all rows after it with a NULL column `a` will be updated. This means that even the execution of a single statement is not atomic.
            dinary dinary made changes -
            Description Isolation Level: Read Uncommitted.
            The behaviors of UPDATE for different rows are inconsistent. Just some of the rows are not updated while others are.


            {code:sql}
            /* init */ drop table if exists t;
            /* init */ create table t(a int, b int);
            /* init */ insert into t values(null, 1), (2, 2), (null, null), (null, 3), (4, null);

            /* s1 */ begin;
            /* s1 */ update t set a = 10 where 1;
            /* s2 */ begin;
            /* s2 */ update t set b = 20 where a; -- blocked
            /* s1 */ commit; -- s2 unblocked
            /* s2 */ commit;

            select * from t;

            +------+------+
            | a | b |
            +------+------+
            | 10 | 1 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}

            The field b of the first row is not updated but other rows are updated.

            After several attempts, I found that the results depend on the distribution of the data in the table rather than the timing.

            If the initial table is like:

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 1 | 1 |
            | 2 | 2 |
            | null | null |
            | null | 3 |
            | 4 | null |
            +------+------+
            {code}

            then, the result will be

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}


            More specifically, if there exists a row whose column `a` is not NULL, and it is the first record from top to bottom whose column `a` is not NULL. Then, all rows before it with a NULL column `a` will not be updated, while all rows after it with a NULL column `a` will be updated. This means that even the execution of a single statement is not atomic.
            Isolation Level: Read Uncommitted & Read Committed.
            The behaviors of UPDATE for different rows are inconsistent. Just some of the rows are not updated while others are.


            {code:sql}
            /* init */ drop table if exists t;
            /* init */ create table t(a int, b int);
            /* init */ insert into t values(null, 1), (2, 2), (null, null), (null, 3), (4, null);

            /* s1 */ begin;
            /* s1 */ update t set a = 10 where 1;
            /* s2 */ begin;
            /* s2 */ update t set b = 20 where a; -- blocked
            /* s1 */ commit; -- s2 unblocked
            /* s2 */ commit;

            select * from t;

            +------+------+
            | a | b |
            +------+------+
            | 10 | 1 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}

            The field b of the first row is not updated but other rows are updated.

            After several attempts, I found that the results depend on the distribution of the data in the table rather than the timing.

            If the initial table is like:

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 1 | 1 |
            | 2 | 2 |
            | null | null |
            | null | 3 |
            | 4 | null |
            +------+------+
            {code}

            then, the result will be

            {code:sql}
            +------+------+
            | a | b |
            +------+------+
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            | 10 | 20 |
            +------+------+
            {code}


            More specifically, if there exists a row whose column `a` is not NULL, and it is the first record from top to bottom whose column `a` is not NULL. Then, all rows before it with a NULL column `a` will not be updated, while all rows after it with a NULL column `a` will be updated. This means that even the execution of a single statement is not atomic.

            This bug can be reproduced under Read Uncommitted and Read Committed.
            Summary Inconsistent behaviors of UPDATE under Read Uncommitted Inconsistent behaviors of UPDATE under RU & RC isolation level
            dinary dinary made changes -
            Labels innodb need_feedback innodb
            dinary dinary made changes -
            Epic/Theme server
            alice Alice Sherepa made changes -
            alice Alice Sherepa made changes -
            Assignee Marko Mäkelä [ marko ]
            serg Sergei Golubchik made changes -
            Fix Version/s 10.5 [ 23123 ]
            Fix Version/s 10.6 [ 24028 ]
            marko Marko Mäkelä made changes -
            serg Sergei Golubchik made changes -
            Workflow MariaDB v3 [ 125162 ] MariaDB v4 [ 143182 ]
            marko Marko Mäkelä made changes -
            Assignee Marko Mäkelä [ marko ] Vladislav Lesin [ vlad.lesin ]
            vlad.lesin Vladislav Lesin made changes -
            Status Open [ 1 ] In Progress [ 3 ]
            vlad.lesin Vladislav Lesin made changes -
            Fix Version/s N/A [ 14700 ]
            Fix Version/s 10.5 [ 23123 ]
            Fix Version/s 10.6 [ 24028 ]
            Resolution Not a Bug [ 6 ]
            Status In Progress [ 3 ] Closed [ 6 ]
            marko Marko Mäkelä made changes -
            Assignee Vladislav Lesin [ vlad.lesin ] Ian Gilfillan [ greenman ]
            Resolution Not a Bug [ 6 ]
            Status Closed [ 6 ] Stalled [ 10000 ]
            marko Marko Mäkelä made changes -
            Component/s Documentation [ 10903 ]
            Component/s Locking [ 10900 ]
            greenman Ian Gilfillan made changes -
            Status Stalled [ 10000 ] Open [ 1 ]
            marko Marko Mäkelä made changes -
            marko Marko Mäkelä made changes -
            Assignee Ian Gilfillan [ greenman ] Marko Mäkelä [ marko ]
            marko Marko Mäkelä made changes -
            Status Open [ 1 ] In Progress [ 3 ]
            marko Marko Mäkelä made changes -
            Status In Progress [ 3 ] Stalled [ 10000 ]
            marko Marko Mäkelä made changes -
            Assignee Marko Mäkelä [ marko ] Vladislav Lesin [ vlad.lesin ]
            marko Marko Mäkelä made changes -
            Fix Version/s 10.6.18 [ 29627 ]
            Fix Version/s 10.11.8 [ 29630 ]
            Fix Version/s 11.0.6 [ 29628 ]
            Fix Version/s 11.1.5 [ 29629 ]
            Fix Version/s 11.2.4 [ 29631 ]
            Fix Version/s 11.4.2 [ 29633 ]
            Fix Version/s N/A [ 14700 ]
            Assignee Vladislav Lesin [ vlad.lesin ] Marko Mäkelä [ marko ]
            Resolution Fixed [ 1 ]
            Status Stalled [ 10000 ] Closed [ 6 ]
            marko Marko Mäkelä made changes -
            vlad.lesin Vladislav Lesin made changes -
            marko Marko Mäkelä made changes -
            marko Marko Mäkelä made changes -

            People

              marko Marko Mäkelä
              dinary dinary
              Votes:
              1 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

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