SQLite

View Ticket
Login
Ticket Hash: f777251dc7abcf45d3f3e86efd09d7951132c30b
Title: Assertion fault following ROLLBACK with running queries
Status: Fixed Type: Code_Defect
Severity: Critical Priority: Immediate
Subsystem: B-Tree Resolution: Fixed
Last Modified: 2009-10-16 20:55:03
Version Found In: 3.6.19
Description:
The following TCL script (run on a TCL interpreter that has the SQLite extension installed) generates an assertion fault:
   file delete -force b2.db
   sqlite3 db b2.db
   db eval {
     CREATE TEMP TABLE t1(x UNIQUE);
     INSERT INTO t1 VALUES(1);
     CREATE TABLE t2(x, y);
     INSERT INTO t2 VALUES(1, 2);
     CREATE TEMP TABLE t3(w, z);
   }
   proc force_rollback {} {
     catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}}
   }
   db function force_rollback force_rollback
   db eval {
     BEGIN IMMEDIATE;
   }
   db eval {
     SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2
   } {
     puts x=$x
   }

Bisecting show the problem was introduced by check-in [c76a366ed4]. (2009-07-04, version 3.6.17)

The failed assert() is the same one reported as Firefox bug 520445.


drh added on 2009-10-15 17:16:17:
A slightly different script causes problems going all the way back to version 3.1.3 (2005-02-19):

  file delete -force b2.db
  sqlite3 db b2.db
  db eval {
    CREATE TEMP TABLE t1(x UNIQUE);
    INSERT INTO t1 VALUES(1);
    CREATE TABLE t2(x, y);
    INSERT INTO t2 VALUES(1, 2);
  }
  proc force_rollback {} {
    set rc [catch {db eval {INSERT OR ROLLBACK INTO t1 VALUES(1)}} msg]
  }
  db function force_rollback force_rollback
  db eval {
    BEGIN IMMEDIATE;
    CREATE TEMP TABLE t3(w, z);
  }
  db eval {
    SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2
  } {
    puts x=$x
  }

drh added on 2009-10-15 18:06:16:
Here is another way to hit the same assert() that does not use the OR ROLLBACK clause. We believe that this is the path that Firefox is using to reach the problem. This route to the assert() was first opened in 3.6.17

  file delete -force b2.db
  sqlite3 db b2.db
  db eval {
    CREATE TEMP TABLE t1(x);
    CREATE TABLE t2(x);
    CREATE TABLE t3(x);
  
    INSERT INTO t1 VALUES(1);
    INSERT INTO t1 VALUES(2);
    INSERT INTO t2 VALUES(1);
    INSERT INTO t2 VALUES(2);
  }
  proc ins {} { db eval {INSERT INTO t3 VALUES('hello')} }
  db function ins ins
  
  db eval { SELECT ins() AS x FROM t2 UNION ALL SELECT ins() AS x FROM t1 }

drh added on 2009-10-16 20:55:03:
Fixed by check-in [174477bca05d019e663fd2b7cd031189ab2e010a]