Added the default_cache_size and default_synchronous pragmas.  Added additional
tests for pragmas.  Added a new speedtest script. (CVS 421)

FossilOrigin-Name: 161c0c5f5db66815e4345c9b5f7a600c03a67475
diff --git a/src/btree.c b/src/btree.c
index a3a269e..7a39089 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.59 2002/03/05 12:41:20 drh Exp $
+** $Id: btree.c,v 1.60 2002/03/06 22:01:35 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -650,6 +650,18 @@
 
 /*
 ** Change the limit on the number of pages allowed the cache.
+**
+** The maximum number of cache pages is set to the absolute
+** value of mxPage.  If mxPage is negative, the pager will
+** operate asynchronously - it will not stop to do fsync()s
+** to insure data is written to the disk surface before
+** continuing.  Transactions still work if synchronous is off,
+** and the database cannot be corrupted if this program
+** crashes.  But if the operating system crashes or there is
+** an abrupt power failure when synchronous is off, the database
+** could be left in an inconsistent and unrecoverable state.
+** Synchronous is on by default so database corruption is not
+** normally a worry.
 */
 int sqliteBtreeSetCacheSize(Btree *pBt, int mxPage){
   sqlitepager_set_cachesize(pBt->pPager, mxPage);
diff --git a/src/build.c b/src/build.c
index 639ba00..108bb4b 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.85 2002/03/05 01:11:13 drh Exp $
+** $Id: build.c,v 1.86 2002/03/06 22:01:36 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1736,10 +1736,30 @@
     sqliteDequote(zRight);
   }
  
-  if( sqliteStrICmp(zLeft,"cache_size")==0 ){
+  /*
+  **  PRAGMA default_cache_size
+  **  PRAGMA default_cache_size=N
+  **
+  ** The first form reports the current persistent setting for the
+  ** page cache size.  The value returned is the maximum number of
+  ** pages in the page cache.  The second form sets both the current
+  ** page cache size value and the persistent page cache size value
+  ** stored in the database file.
+  **
+  ** The default cache size is stored in meta-value 2 of page 1 of the
+  ** database file.  The cache size is actually the absolute value of
+  ** this memory location.  The sign of meta-value 2 determines the
+  ** synchronous setting.  A negative value means synchronous is off
+  ** and a positive value means synchronous is on.
+  */
+  if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
     static VdbeOp getCacheSize[] = {
       { OP_ReadCookie,  0, 2,        0},
       { OP_AbsValue,    0, 0,        0},
+      { OP_Dup,         0, 0,        0},
+      { OP_Integer,     0, 0,        0},
+      { OP_Ne,          0, 6,        0},
+      { OP_Integer,     MAX_PAGES,0, 0},
       { OP_ColumnCount, 1, 0,        0},
       { OP_ColumnName,  0, 0,        "cache_size"},
       { OP_Callback,    1, 0,        0},
@@ -1760,10 +1780,71 @@
       sqliteVdbeAddOp(v, OP_Negative, 0, 0);
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
       sqliteEndWriteOperation(pParse);
+      db->cache_size = db->cache_size<0 ? -size : size;
+      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
     }
   }else
 
-  if( sqliteStrICmp(zLeft,"synchronous")==0 ){
+  /*
+  **  PRAGMA cache_size
+  **  PRAGMA cache_size=N
+  **
+  ** The first form reports the current local setting for the
+  ** page cache size.  The local setting can be different from
+  ** the persistent cache size value that is stored in the database
+  ** file itself.  The value returned is the maximum number of
+  ** pages in the page cache.  The second form sets the local
+  ** page cache size value.  It does not change the persistent
+  ** cache size stored on the disk so the cache size will revert
+  ** to its default value when the database is closed and reopened.
+  ** N should be a positive integer.
+  */
+  if( sqliteStrICmp(zLeft,"cache_size")==0 ){
+    static VdbeOp getCacheSize[] = {
+      { OP_ColumnCount, 1, 0,        0},
+      { OP_ColumnName,  0, 0,        "cache_size"},
+      { OP_Callback,    1, 0,        0},
+    };
+    Vdbe *v = sqliteGetVdbe(pParse);
+    if( v==0 ) return;
+    if( pRight->z==pLeft->z ){
+      int size = db->cache_size;;
+      if( size<0 ) size = -size;
+      sqliteVdbeAddOp(v, OP_Integer, size, 0);
+      sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
+    }else{
+      int size = atoi(zRight);
+      if( size<0 ) size = -size;
+      if( db->cache_size<0 ) size = -size;
+      db->cache_size = size;
+      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
+    }
+  }else
+
+  /*
+  **  PRAGMA default_synchronous
+  **  PRAGMA default_synchronous=BOOLEAN
+  **
+  ** The first form returns the persistent value of the "synchronous" setting
+  ** that is stored in the database.  This is the synchronous setting that
+  ** is used whenever the database is opened unless overridden by a separate
+  ** "synchronous" pragma.  The second form changes the persistent and the
+  ** local synchronous setting to the value given.
+  **
+  ** If synchronous is on, SQLite will do an fsync() system call at strategic
+  ** points to insure that all previously written data has actually been
+  ** written onto the disk surface before continuing.  This mode insures that
+  ** the database will always be in a consistent state event if the operating
+  ** system crashes or power to the computer is interrupted unexpectedly.
+  ** When synchronous is off, SQLite will not wait for changes to actually
+  ** be written to the disk before continuing.  As soon as it hands changes
+  ** to the operating system, it assumes that the changes are permanent and
+  ** it continues going.  The database cannot be corrupted by a program crash
+  ** even with synchronous off, but an operating system crash or power loss
+  ** could potentially corrupt data.  On the other hand, synchronous off is
+  ** faster than synchronous on.
+  */
+  if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
     static VdbeOp getSync[] = {
       { OP_Integer,     0, 0,        0},
       { OP_ReadCookie,  0, 2,        0},
@@ -1780,14 +1861,52 @@
       sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
     }else{
       int addr;
+      int size = db->cache_size;
+      if( size<0 ) size = -size;
       sqliteBeginWriteOperation(pParse);
       sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
+      addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
+      sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
+      sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
       sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
       if( !getBoolean(zRight) ){
         sqliteVdbeAddOp(v, OP_Negative, 0, 0);
+        size = -size;
       }
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
       sqliteEndWriteOperation(pParse);
+      db->cache_size = size;
+      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
+    }
+  }else
+
+  /*
+  **   PRAGMA synchronous
+  **   PRAGMA synchronous=BOOLEAN
+  **
+  ** Return or set the local value of the synchronous flag.  Changing
+  ** the local value does not make changes to the disk file and the
+  ** default value will be restored the next time the database is
+  ** opened.
+  */
+  if( sqliteStrICmp(zLeft,"synchronous")==0 ){
+    static VdbeOp getSync[] = {
+      { OP_ColumnCount, 1, 0,        0},
+      { OP_ColumnName,  0, 0,        "synchronous"},
+      { OP_Callback,    1, 0,        0},
+    };
+    Vdbe *v = sqliteGetVdbe(pParse);
+    if( v==0 ) return;
+    if( pRight->z==pLeft->z ){
+      sqliteVdbeAddOp(v, OP_Integer, db->cache_size>=0, 0);
+      sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
+    }else{
+      int size = db->cache_size;
+      if( size<0 ) size = -size;
+      if( !getBoolean(zRight) ) size = -size;
+      db->cache_size = size;
+      sqliteBtreeSetCacheSize(db->pBe, db->cache_size);
     }
   }else
 
diff --git a/src/main.c b/src/main.c
index 62f0952..3895079 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.67 2002/03/05 01:11:14 drh Exp $
+** $Id: main.c,v 1.68 2002/03/06 22:01:36 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -44,9 +44,9 @@
   switch( argv[0][0] ){
     case 'c': {  /* Recommended pager cache size */
       int size = atoi(argv[3]);
-      if( size!=0 ){
-        sqliteBtreeSetCacheSize(db->pBe, size);
-      }
+      if( size==0 ){ size = MAX_PAGES; }
+      db->cache_size = size;
+      sqliteBtreeSetCacheSize(db->pBe, size);
       break;
     }
     case 'f': {  /* File format */
diff --git a/src/pager.c b/src/pager.c
index 1f0fb3a..ced0016 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.43 2002/03/05 12:41:20 drh Exp $
+** @(#) $Id: pager.c,v 1.44 2002/03/06 22:01:36 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -434,6 +434,13 @@
 
 /*
 ** Change the maximum number of in-memory pages that are allowed.
+**
+** The maximum number is the absolute value of the mxPage parameter.
+** If mxPage is negative, the noSync flag is also set.  noSync bypasses
+** calls to sqliteOsSync().  The pager runs much faster with noSync on,
+** but if the operating system crashes or there is an abrupt power 
+** failure, the database file might be left in an inconsistent and
+** unrepairable state.  
 */
 void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
   if( mxPage>=0 ){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 3520a94..e404a73 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.102 2002/03/05 01:11:14 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.103 2002/03/06 22:01:36 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -155,6 +155,7 @@
   int file_format;              /* What file format version is this database? */
   int schema_cookie;            /* Magic number that changes with the schema */
   int next_cookie;              /* Value of schema_cookie after commit */
+  int cache_size;               /* Number of pages to use in the cache */
   int nTable;                   /* Number of tables in the database */
   void *pBusyArg;               /* 1st Argument to the busy callback */
   int (*xBusyCallback)(void *,const char*,int);  /* The busy callback */
diff --git a/src/vdbe.c b/src/vdbe.c
index adb3fbe..f37d57e 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.132 2002/03/06 03:08:26 drh Exp $
+** $Id: vdbe.c,v 1.133 2002/03/06 22:01:36 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -4309,7 +4309,8 @@
   memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);;
   if( aStack[tos].flags & STK_Str ){
     zStack[tos] = p->aMem[i].z;
-    aStack[tos].flags = STK_Str | STK_Static;
+    aStack[tos].flags |= STK_Static;
+    aStack[tos].flags &= ~STK_Dyn;
   }
   break;
 }