aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--manifest31
-rw-r--r--manifest.uuid2
-rw-r--r--src/btree.c114
-rw-r--r--src/btreeInt.h6
-rw-r--r--src/vacuum.c6
-rw-r--r--src/vdbe.c6
-rw-r--r--test/tkt-f777251dc7a.test99
7 files changed, 202 insertions, 62 deletions
diff --git a/manifest b/manifest
index 2c69aa7e2..a7d88c866 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,8 @@
-C Fix\sa\sproblem\sin\sthe\sanalyze3.test\sscript.
-D 2009-10-16T15:59:35
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Merge\sthe\ssqlite3_reoptimize()\schanges\sinto\sthe\strunk.
+D 2009-10-16T16:21:52
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -106,9 +109,9 @@ F src/auth.c a5471a6951a18f79d783da34be22cd94dfbe603a
F src/backup.c 6f1c2d9862c8a3feb7739dfcca02c1f5352e37f3
F src/bitvec.c ed215b95734045e58358c3b3e16448f8fe6a235a
F src/btmutex.c 0f43a75bb5b8147b386e8e1c3e71ba734e3863b7
-F src/btree.c 9c425425784c5d569bc0309c22251698ba906451
+F src/btree.c b2d060e41b4318fb5e52d80b75e19bcef1b1f2db
F src/btree.h 577448a890c2ab9b21e6ab74f073526184bceebe
-F src/btreeInt.h 1c86297e69380f6577e7ae67452597dd8d5c2705
+F src/btreeInt.h cce1c3360cd5549ffa79f981951dfae93118ad79
F src/build.c 3c5762687d0554ebe8844dfaddb828fcc15fe16d
F src/callback.c 10d237171472865f58fb07d515737238c9e06688
F src/complete.c 5ad5c6cd4548211867c204c41a126d73a9fbcea0
@@ -205,8 +208,8 @@ F src/trigger.c 2053afa9952f69cf451bc0e6ea88072701f2925e
F src/update.c 2c8a64237e4fae604468d14380b877d169545b63
F src/utf.c 99cf927eabb104621ba889ac0dd075fc1657ad30
F src/util.c 59d4e9456bf1fe581f415a783fa0cee6115c8f35
-F src/vacuum.c 869d08eaab64e2a4eaf4ef9ea34b851892b65a75
-F src/vdbe.c a03993ed188c9b2c575766dfe2b8cdc9f0bd2262
+F src/vacuum.c f2347520907ee4ec867c9b804d24456b0fd912a7
+F src/vdbe.c f0d6e7dbd4515758c188c9dd7025eb9dfcf021e0
F src/vdbe.h 1fb725c38df7f79dc60e9a61cb368152d9457e3c
F src/vdbeInt.h aafda2e9761298e12ef0a3e8b5caed9aaf9c7592
F src/vdbeapi.c a7669f434f1fb53457343e7e85d06d695f7bb4e8
@@ -590,6 +593,7 @@ F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
+F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
F test/tkt1443.test bacc311da5c96a227bf8c167e77a30c99f8e8368
F test/tkt1444.test a9d72f9e942708bd82dde6c707da61c489e213e9
@@ -758,7 +762,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9f0937066184421f23453ceb451fd726c75cb593
-R 86e25f1b6a52bb9c63882796d734f555
-U dan
-Z fec49abff05b5e5ceea062664695ce9e
+P 32966ba4796e70d0afcff6abdda9bdcba08b098a 9f0937066184421f23453ceb451fd726c75cb593 61174aea74db59f6792e275aa366b7f0e1f2270b
+R 61972980031ca23020de60e9d0fbe40d
+U drh
+Z 1bd496ba22406bf1b4185ebae8272187
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFK2J2moxKgR168RlERAnBlAJ0TOp4dztyQ8x3H8zZLjMwtg9ofCQCeM/sa
+FdOVdtjuYXVkiT+lGN/mPWo=
+=+vEN
+-----END PGP SIGNATURE-----
diff --git a/manifest.uuid b/manifest.uuid
index 2cb492295..96ecc2564 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-61174aea74db59f6792e275aa366b7f0e1f2270b \ No newline at end of file
+50136840d54674c239613265ebbacaabf215f4e2 \ No newline at end of file
diff --git a/src/btree.c b/src/btree.c
index a9ab44504..7c95d68dc 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -90,22 +90,24 @@ int sqlite3_enable_shared_cache(int enable){
#ifdef SQLITE_DEBUG
/*
-** This function is only used as part of an assert() statement. It checks
-** that connection p holds the required locks to read or write to the
-** b-tree with root page iRoot. If so, true is returned. Otherwise, false.
-** For example, when writing to a table b-tree with root-page iRoot via
+**** This function is only used as part of an assert() statement. ***
+**
+** Check to see if pBtree holds the required locks to read or write to the
+** table with root page iRoot. Return 1 if it does and 0 if not.
+**
+** For example, when writing to a table with root-page iRoot via
** Btree connection pBtree:
**
** assert( hasSharedCacheTableLock(pBtree, iRoot, 0, WRITE_LOCK) );
**
-** When writing to an index b-tree that resides in a sharable database, the
+** When writing to an index that resides in a sharable database, the
** caller should have first obtained a lock specifying the root page of
-** the corresponding table b-tree. This makes things a bit more complicated,
-** as this module treats each b-tree as a separate structure. To determine
-** the table b-tree corresponding to the index b-tree being written, this
+** the corresponding table. This makes things a bit more complicated,
+** as this module treats each table as a separate structure. To determine
+** the table corresponding to the index being written, this
** function has to search through the database schema.
**
-** Instead of a lock on the b-tree rooted at page iRoot, the caller may
+** Instead of a lock on the table/index rooted at page iRoot, the caller may
** hold a write-lock on the schema table (root page 1). This is also
** acceptable.
*/
@@ -119,20 +121,25 @@ static int hasSharedCacheTableLock(
Pgno iTab = 0;
BtLock *pLock;
- /* If this b-tree database is not shareable, or if the client is reading
+ /* If this database is not shareable, or if the client is reading
** and has the read-uncommitted flag set, then no lock is required.
- ** In these cases return true immediately. If the client is reading
- ** or writing an index b-tree, but the schema is not loaded, then return
- ** true also. In this case the lock is required, but it is too difficult
- ** to check if the client actually holds it. This doesn't happen very
- ** often. */
+ ** Return true immediately.
+ */
if( (pBtree->sharable==0)
|| (eLockType==READ_LOCK && (pBtree->db->flags & SQLITE_ReadUncommitted))
- || (isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0 ))
){
return 1;
}
+ /* If the client is reading or writing an index and the schema is
+ ** not loaded, then it is too difficult to actually check to see if
+ ** the correct locks are held. So do not bother - just return true.
+ ** This case does not come up very often anyhow.
+ */
+ if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){
+ return 1;
+ }
+
/* Figure out the root-page that the lock should be held on. For table
** b-trees, this is just the root page of the b-tree being read or
** written. For index b-trees, it is the root page of the associated
@@ -164,14 +171,24 @@ static int hasSharedCacheTableLock(
/* Failed to find the required lock. */
return 0;
}
+#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
/*
-** This function is also used as part of assert() statements only. It
-** returns true if there exist one or more cursors open on the table
-** with root page iRoot that do not belong to either connection pBtree
-** or some other connection that has the read-uncommitted flag set.
+**** This function may be used as part of assert() statements only. ****
+**
+** Return true if it would be illegal for pBtree to write into the
+** table or index rooted at iRoot because other shared connections are
+** simultaneously reading that same table or index.
**
-** For example, before writing to page iRoot:
+** It is illegal for pBtree to write if some other Btree object that
+** shares the same BtShared object is currently reading or writing
+** the iRoot table. Except, if the other Btree object has the
+** read-uncommitted flag set, then it is OK for the other object to
+** have a read cursor.
+**
+** For example, before writing to any part of the table or index
+** rooted at page iRoot, one should call:
**
** assert( !hasReadConflicts(pBtree, iRoot) );
*/
@@ -190,7 +207,7 @@ static int hasReadConflicts(Btree *pBtree, Pgno iRoot){
#endif /* #ifdef SQLITE_DEBUG */
/*
-** Query to see if btree handle p may obtain a lock of type eLock
+** Query to see if Btree handle p may obtain a lock of type eLock
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
** SQLITE_OK if the lock may be obtained (by calling
** setSharedCacheTableLock()), or SQLITE_LOCKED if not.
@@ -211,7 +228,7 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
assert( eLock==READ_LOCK || (p==pBt->pWriter && p->inTrans==TRANS_WRITE) );
assert( eLock==READ_LOCK || pBt->inTransaction==TRANS_WRITE );
- /* This is a no-op if the shared-cache is not enabled */
+ /* This routine is a no-op if the shared-cache is not enabled */
if( !p->sharable ){
return SQLITE_OK;
}
@@ -257,10 +274,10 @@ static int querySharedCacheTableLock(Btree *p, Pgno iTab, u8 eLock){
**
** This function assumes the following:
**
-** (a) The specified b-tree connection handle is connected to a sharable
-** b-tree database (one with the BtShared.sharable) flag set, and
+** (a) The specified Btree object p is connected to a sharable
+** database (one with the BtShared.sharable flag set), and
**
-** (b) No other b-tree connection handle holds a lock that conflicts
+** (b) No other Btree objects hold a lock that conflicts
** with the requested lock (i.e. querySharedCacheTableLock() has
** already been called and returned SQLITE_OK).
**
@@ -325,9 +342,9 @@ static int setSharedCacheTableLock(Btree *p, Pgno iTable, u8 eLock){
#ifndef SQLITE_OMIT_SHARED_CACHE
/*
** Release all the table locks (locks obtained via calls to
-** the setSharedCacheTableLock() procedure) held by Btree handle p.
+** the setSharedCacheTableLock() procedure) held by Btree object p.
**
-** This function assumes that handle p has an open read or write
+** This function assumes that Btree p has an open read or write
** transaction. If it does not, then the BtShared.isPending variable
** may be incorrectly cleared.
*/
@@ -360,7 +377,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
pBt->isExclusive = 0;
pBt->isPending = 0;
}else if( pBt->nTransaction==2 ){
- /* This function is called when connection p is concluding its
+ /* This function is called when Btree p is concluding its
** transaction. If there currently exists a writer, and p is not
** that writer, then the number of locks held by connections other
** than the writer must be about to drop to zero. In this case
@@ -374,7 +391,7 @@ static void clearAllSharedCacheTableLocks(Btree *p){
}
/*
-** This function changes all write-locks held by connection p to read-locks.
+** This function changes all write-locks held by Btree p into read-locks.
*/
static void downgradeAllSharedCacheTableLocks(Btree *p){
BtShared *pBt = p->pBt;
@@ -395,9 +412,11 @@ static void downgradeAllSharedCacheTableLocks(Btree *p){
static void releasePage(MemPage *pPage); /* Forward reference */
/*
-** Verify that the cursor holds a mutex on the BtShared
+***** This routine is used inside of assert() only ****
+**
+** Verify that the cursor holds the mutex on its BtShared
*/
-#ifndef NDEBUG
+#ifdef SQLITE_DEBUG
static int cursorHoldsMutex(BtCursor *p){
return sqlite3_mutex_held(p->pBt->mutex);
}
@@ -428,7 +447,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
/*
** This function is called before modifying the contents of a table
-** b-tree to invalidate any incrblob cursors that are open on the
+** to invalidate any incrblob cursors that are open on the
** row or one of the rows being modified.
**
** If argument isClearTable is true, then the entire contents of the
@@ -437,7 +456,7 @@ static void invalidateAllOverflowCache(BtShared *pBt){
**
** Otherwise, if argument isClearTable is false, then the row with
** rowid iRow is being replaced or deleted. In this case invalidate
-** only those incrblob cursors open on this specific row.
+** only those incrblob cursors open on that specific row.
*/
static void invalidateIncrblobCursors(
Btree *pBtree, /* The database file to check */
@@ -455,10 +474,11 @@ static void invalidateIncrblobCursors(
}
#else
+ /* Stub functions when INCRBLOB is omitted */
#define invalidateOverflowCache(x)
#define invalidateAllOverflowCache(x)
#define invalidateIncrblobCursors(x,y,z)
-#endif
+#endif /* SQLITE_OMIT_INCRBLOB */
/*
** Set bit pgno of the BtShared.pHasContent bitvec. This is called
@@ -491,7 +511,7 @@ static void invalidateIncrblobCursors(
** The solution is the BtShared.pHasContent bitvec. Whenever a page is
** moved to become a free-list leaf page, the corresponding bit is
** set in the bitvec. Whenever a leaf page is extracted from the free-list,
-** optimization 2 above is ommitted if the corresponding bit is already
+** optimization 2 above is omitted if the corresponding bit is already
** set in BtShared.pHasContent. The contents of the bitvec are cleared
** at the end of every transaction.
*/
@@ -587,8 +607,8 @@ static int saveCursorPosition(BtCursor *pCur){
}
/*
-** Save the positions of all cursors except pExcept open on the table
-** with root-page iRoot. Usually, this is called just before cursor
+** Save the positions of all cursors (except pExcept) that are open on
+** the table with root-page iRoot. Usually, this is called just before cursor
** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).
*/
static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){
@@ -993,7 +1013,10 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
assert( nSize==debuginfo.nSize );
return (u16)nSize;
}
-#ifndef NDEBUG
+
+#ifdef SQLITE_DEBUG
+/* This variation on cellSizePtr() is used inside of assert() statements
+** only. */
static u16 cellSize(MemPage *pPage, int iCell){
return cellSizePtr(pPage, findCell(pPage, iCell));
}
@@ -2965,18 +2988,13 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
*/
static void btreeEndTransaction(Btree *p){
BtShared *pBt = p->pBt;
- BtCursor *pCsr;
assert( sqlite3BtreeHoldsMutex(p) );
- /* Search for a cursor held open by this b-tree connection. If one exists,
- ** then the transaction will be downgraded to a read-only transaction
- ** instead of actually concluded. A subsequent call to CommitPhaseTwo()
- ** or Rollback() will finish the transaction and unlock the database. */
- for(pCsr=pBt->pCursor; pCsr && pCsr->pBtree!=p; pCsr=pCsr->pNext);
- assert( pCsr==0 || p->inTrans>TRANS_NONE );
-
btreeClearHasContent(pBt);
- if( pCsr ){
+ if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){
+ /* If there are other active statements that belong to this database
+ ** handle, downgrade to a read-only transaction. The other statements
+ ** may still be reading from the database. */
downgradeAllSharedCacheTableLocks(p);
p->inTrans = TRANS_READ;
}else{
diff --git a/src/btreeInt.h b/src/btreeInt.h
index 239439b4a..a2559eeb5 100644
--- a/src/btreeInt.h
+++ b/src/btreeInt.h
@@ -329,8 +329,8 @@ struct BtLock {
** this structure.
**
** For some database files, the same underlying database cache might be
-** shared between multiple connections. In that case, each contection
-** has it own pointer to this object. But each instance of this object
+** shared between multiple connections. In that case, each connection
+** has it own instance of this object. But each instance of this object
** points to the same BtShared object. The database cache and the
** schema associated with the database file are all contained within
** the BtShared object.
@@ -471,7 +471,7 @@ struct CellInfo {
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
**
-** When a single database file can shared by two more database connections,
+** A single database file can shared by two more database connections,
** but cursors cannot be shared. Each cursor is associated with a
** particular database connection identified BtCursor.pBtree.db.
**
diff --git a/src/vacuum.c b/src/vacuum.c
index 00f3511d8..8f9221e5c 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -130,6 +130,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
+ /* The call to execSql() to attach the temp database has left the file
+ ** locked (as there was more than one active statement when the transaction
+ ** to read the schema was concluded. Unlock it here so that this doesn't
+ ** cause problems for the call to BtreeSetPageSize() below. */
+ sqlite3BtreeCommit(pTemp);
+
nRes = sqlite3BtreeGetReserve(pMain);
/* A VACUUM cannot change the pagesize of an encrypted database. */
diff --git a/src/vdbe.c b/src/vdbe.c
index bf39585c9..6847b9027 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -2853,6 +2853,7 @@ case OP_SetCookie: { /* in3 */
/* Invalidate all prepared statements whenever the TEMP database
** schema is changed. Ticket #1644 */
sqlite3ExpirePreparedStatements(db);
+ p->expired = 0;
}
break;
}
@@ -2970,6 +2971,11 @@ case OP_OpenWrite: {
VdbeCursor *pCur;
Db *pDb;
+ if( p->expired ){
+ rc = SQLITE_ABORT;
+ break;
+ }
+
nField = 0;
pKeyInfo = 0;
p2 = pOp->p2;
diff --git a/test/tkt-f777251dc7a.test b/test/tkt-f777251dc7a.test
new file mode 100644
index 000000000..6f0b43fa8
--- /dev/null
+++ b/test/tkt-f777251dc7a.test
@@ -0,0 +1,99 @@
+# 2009 October 16
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.
+#
+# This file implements tests to verify that ticket [f777251dc7a] has been
+# fixed.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_test tkt-f7772-1.1 {
+ execsql {
+ 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
+
+do_test tkt-f7772-1.2 {
+ catchsql {
+ BEGIN IMMEDIATE;
+ SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2;
+ }
+} {1 {callback requested query abort}}
+do_test tkt-f7772-1.3 {
+ sqlite3_get_autocommit db
+} {1}
+
+do_test tkt-f7772-2.1 {
+ execsql {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS t2;
+ DROP TABLE IF EXISTS t3;
+
+ CREATE TEMP TABLE t1(x UNIQUE);
+ INSERT INTO t1 VALUES(1);
+ CREATE TABLE t2(x, y);
+ INSERT INTO t2 VALUES(1, 2);
+ }
+} {}
+do_test tkt-f7772-2.2 {
+ execsql {
+ BEGIN IMMEDIATE;
+ CREATE TEMP TABLE t3(w, z);
+ }
+ catchsql {
+ SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2
+ }
+} {1 {callback requested query abort}}
+do_test tkt-f7772-2.3 {
+ sqlite3_get_autocommit db
+} {1}
+
+do_test tkt-f7772-3.1 {
+ execsql {
+ DROP TABLE IF EXISTS t1;
+ DROP TABLE IF EXISTS t2;
+ DROP TABLE IF EXISTS t3;
+
+ 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
+
+do_test tkt-f7772-3.2 {
+ execsql {
+ SELECT ins() AS x FROM t2 UNION ALL SELECT ins() AS x FROM t1
+ }
+} {{} {} {} {}}
+do_test tkt-f7772-3.3 {
+ execsql { SELECT * FROM t3 }
+} {hello hello hello hello}
+
+finish_test