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);

Reply via email to