I'm having problems with code that starts a transaction, creates a table, commits, begins a new transaction, creates a temporary table, inserts data into the temporary table, and the inserts into the table the results of a select from the temporary table. The insert statement results in a SQLITE_ERROR on sqlite3_step. This is because there are two open btree cursors, one invalid read cursor, one write cursor. I don't totally understand the significance of the isValid flag of a btree cursor, but if I ignore cursors with isValid == 0 in checkReadLocks(), the attached test case succeeds.
Current HEAD CVS has 15 failures both with and without the attached patch, but this is in a subtle area of the database, so I'm not certain this is the right fix. Cheers, Matt
#include <assert.h> #include <sqlite3.h> #include <stdio.h> #include <stdlib.h> void exec(sqlite3 *pDb, const char *sql) { sqlite3_stmt *pStmt; const char *zLeftover; int rc; rc = sqlite3_prepare(pDb, sql, -1, &pStmt, &zLeftover); if (rc != SQLITE_OK) { printf("error occurred while preparing statement: %s\n", sqlite3_errmsg(pDb)); abort(); } assert(rc == SQLITE_OK); assert(*zLeftover == '\0'); rc = sqlite3_step(pStmt); if (rc != SQLITE_DONE) { printf("error: sqlite3_step returned %d, expected %d.\n", rc, SQLITE_DONE); abort(); } rc = sqlite3_finalize(pStmt); assert(rc == SQLITE_OK); } int main(void) { sqlite3 *pDb; int rc; rc = sqlite3_open(":memory:", &pDb); assert(rc == SQLITE_OK); exec(pDb, "BEGIN"); exec(pDb, "CREATE TABLE Dependencies(depId integer primary key," "class integer, name str, flag str);"); exec(pDb, "COMMIT"); exec(pDb, "BEGIN"); exec(pDb, "CREATE TEMPORARY TABLE DepCheck(troveId INT, depNum INT, " "flagCount INT, isProvides BOOL, class INTEGER, name STRING, " "flag STRING)"); exec(pDb, "INSERT INTO DepCheck " "VALUES(-1, 0, 1, 0, 2, 'libc.so.6', 'GLIBC_2.0')"); exec(pDb, "INSERT INTO Dependencies \ SELECT DISTINCT \ NULL, \ DepCheck.class, \ DepCheck.name, \ DepCheck.flag \ FROM DepCheck LEFT OUTER JOIN Dependencies ON \ DepCheck.class == Dependencies.class AND \ DepCheck.name == Dependencies.name AND \ DepCheck.flag == Dependencies.flag \ WHERE \ Dependencies.depId is NULL"); exec(pDb, "ROLLBACK"); printf("success\n"); return 0; }
Index: src/btree.c =================================================================== RCS file: /sqlite/sqlite/src/btree.c,v retrieving revision 1.189 diff -u -r1.189 btree.c --- src/btree.c 8 Sep 2004 20:13:05 -0000 1.189 +++ src/btree.c 15 Sep 2004 18:54:31 -0000 @@ -3498,7 +3498,7 @@ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; for(p=pBt->pCursor; p; p=p->pNext){ - if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; + if( p->pgnoRoot!=pgnoRoot || p==pExclude || p->isValid == 0) continue; if( p->wrFlag==0 ) return SQLITE_LOCKED; if( p->pPage->pgno!=p->pgnoRoot ){ moveToRoot(p);