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