Bug fix: sqlite_exec() would sometimes return SQLITE_PROTOCOL when it
should have returned SQLITE_BUSY.  There was also a deadlock that the
previous bug was masking. (CVS 322)

FossilOrigin-Name: 585ed5ebf1c1afc8ae1d569b121208018d8ecd49
diff --git a/src/btree.c b/src/btree.c
index 574627d..00f8982 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.41 2001/11/23 00:24:12 drh Exp $
+** $Id: btree.c,v 1.42 2001/12/05 00:21:20 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -677,6 +677,24 @@
 }
 
 /*
+** If there are no outstanding cursors and we are not in the middle
+** of a transaction but there is a read lock on the database, then
+** this routine unrefs the first page of the database file which 
+** has the effect of releasing the read lock.
+**
+** If there are any outstanding cursors, this routine is a no-op.
+**
+** If there is a transaction in progress, this routine is a no-op.
+*/
+static void unlockBtreeIfUnused(Btree *pBt){
+  if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
+    sqlitepager_unref(pBt->page1);
+    pBt->page1 = 0;
+    pBt->inTrans = 0;
+  }
+}
+
+/*
 ** Create a new database by initializing the first two pages of the
 ** file.
 */
@@ -725,33 +743,19 @@
       return rc;
     }
   }
-  if( !sqlitepager_isreadonly(pBt->pPager) ){
-    rc = sqlitepager_write(pBt->page1);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
+  if( sqlitepager_isreadonly(pBt->pPager) ){
+    return SQLITE_READONLY;
+  }
+  rc = sqlitepager_write(pBt->page1);
+  if( rc==SQLITE_OK ){
     rc = newDatabase(pBt);
   }
-  pBt->inTrans = 1;
-  return rc;
-}
-
-/*
-** If there are no outstanding cursors and we are not in the middle
-** of a transaction but there is a read lock on the database, then
-** this routine unrefs the first page of the database file which 
-** has the effect of releasing the read lock.
-**
-** If there are any outstanding cursors, this routine is a no-op.
-**
-** If there is a transaction in progress, this routine is a no-op.
-*/
-static void unlockBtreeIfUnused(Btree *pBt){
-  if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
-    sqlitepager_unref(pBt->page1);
-    pBt->page1 = 0;
-    pBt->inTrans = 0;
+  if( rc==SQLITE_OK ){
+    pBt->inTrans = 1;
+  }else{
+    unlockBtreeIfUnused(pBt);
   }
+  return rc;
 }
 
 /*
diff --git a/src/build.c b/src/build.c
index 625be67..006f459 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.57 2001/11/22 00:01:27 drh Exp $
+** $Id: build.c,v 1.58 2001/12/05 00:21:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -553,7 +553,7 @@
 */
 static void changeCookie(sqlite *db){
   if( db->next_cookie==db->schema_cookie ){
-    db->next_cookie = db->schema_cookie + sqliteRandomByte(db) + 1;
+    db->next_cookie = db->schema_cookie + sqliteRandomByte() + 1;
     db->flags |= SQLITE_InternChanges;
   }
 }
diff --git a/src/main.c b/src/main.c
index a9beba9..d59c612 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.50 2001/11/23 00:24:12 drh Exp $
+** $Id: main.c,v 1.51 2001/12/05 00:21:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -265,7 +265,7 @@
   if( db==0 ) goto no_mem_on_open;
   sqliteHashInit(&db->tblHash, SQLITE_HASH_STRING, 0);
   sqliteHashInit(&db->idxHash, SQLITE_HASH_STRING, 0);
-  db->nextRowid = sqliteRandomInteger(db);
+  db->nextRowid = sqliteRandomInteger();
   
   /* Open the backend database driver */
   rc = sqliteBtreeOpen(zFilename, mode, MAX_PAGES, &db->pBe);
diff --git a/src/os.h b/src/os.h
index 31edc76..f90b525 100644
--- a/src/os.h
+++ b/src/os.h
@@ -59,8 +59,8 @@
 int sqliteOsUnlock(OsFile);
 int sqliteOsRandomSeed(char*);
 int sqliteOsSleep(int ms);
-void sqliteOsEnterMutex();
-void sqliteOsLeaveMutex();
+void sqliteOsEnterMutex(void);
+void sqliteOsLeaveMutex(void);
 
 
 
diff --git a/src/pager.c b/src/pager.c
index a620a3a..378a9e4 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.31 2001/11/22 00:01:27 drh Exp $
+** @(#) $Id: pager.c,v 1.32 2001/12/05 00:21:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -955,13 +955,20 @@
     }
     sqliteOsUnlock(pPager->fd);
     if( sqliteOsLock(pPager->fd, 1)!=SQLITE_OK ){
+      sqliteOsUnlock(pPager->fd);
+      rc = sqliteOsLock(pPager->fd, 0);
       sqliteFree(pPager->aInJournal);
       sqliteOsClose(pPager->jfd);
       sqliteOsDelete(pPager->zJournal);
       pPager->journalOpen = 0;
-      pPager->state = SQLITE_UNLOCK;
-      pPager->errMask |= PAGER_ERR_LOCK;
-      return SQLITE_PROTOCOL;
+      if( rc ){
+        pPager->state = SQLITE_UNLOCK;
+        pPager->errMask |= PAGER_ERR_LOCK;
+        return SQLITE_PROTOCOL;
+      }else{
+        pPager->state = SQLITE_READLOCK;
+        return SQLITE_BUSY;
+      }
     }
     pPager->state = SQLITE_WRITELOCK;
     sqlitepager_pagecount(pPager);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b80eac9..03e0504 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.71 2001/11/22 00:01:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.72 2001/12/05 00:21:20 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -519,8 +519,8 @@
 int sqliteExprAnalyzeAggregates(Parse*, Expr*);
 void sqliteParseInfoReset(Parse*);
 Vdbe *sqliteGetVdbe(Parse*);
-int sqliteRandomByte();
-int sqliteRandomInteger();
+int sqliteRandomByte(void);
+int sqliteRandomInteger(void);
 void sqliteBeginTransaction(Parse*);
 void sqliteCommitTransaction(Parse*);
 void sqliteRollbackTransaction(Parse*);