]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not put a write lock on the main database file when writing to a temporary
authordrh <drh@noemail.net>
Sat, 14 Sep 2002 13:47:32 +0000 (13:47 +0000)
committerdrh <drh@noemail.net>
Sat, 14 Sep 2002 13:47:32 +0000 (13:47 +0000)
table. (CVS 750)

FossilOrigin-Name: 3f253afe15d4f7392555f340a41d780d1248087f

12 files changed:
manifest
manifest.uuid
src/build.c
src/delete.c
src/insert.c
src/sqliteInt.h
src/tclsqlite.c
src/trigger.c
src/update.c
src/vdbe.c
test/lock.test
test/tclsqlite.test

index 0a4b94c29fa927fc1bf4699ffb5701c7fc637182..4938f281182aca034a7fadae3cd52d55742faf97 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Rename\sall\stests\sso\sthat\sthe\sfirst\spart\sof\sthe\stest\sname\scorresponds\sto\sthe\nfile\sthat\scontains\sthat\stest.\s\sThis\smakes\sit\smuch\seasier\sto\sfind\sa\sparticular\ntest\safter\sit\sfail.\s(CVS\s749)
-D 2002-09-14T12:04:56
+C Do\snot\sput\sa\swrite\slock\son\sthe\smain\sdatabase\sfile\swhen\swriting\sto\sa\stemporary\ntable.\s(CVS\s750)
+D 2002-09-14T13:47:32
 F Makefile.in d6c9a85c2a5e696843201d090dcf8bf2f8716f2a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -20,14 +20,14 @@ F spec.template 238f7db425a78dc1bb7682e56e3834c7270a3f5e
 F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea
 F src/btree.c 8024b87635c2adf133f153f1bb595125ec1c7d7b
 F src/btree.h 0ca6c2631338df62e4f7894252d9347ae234eda9
-F src/build.c 0116afe4f67687206364c4d1e88dc07aefc661de
-F src/delete.c c9f59ee217e062eb9de7b64b76b5cfff42b2f028
+F src/build.c d41b8da6b52ff84b235a785b226c37f3090ed276
+F src/delete.c aad9d4051ab46e6f6391ea5f7b8994a7c05bdd15
 F src/encode.c 346b12b46148506c32038524b95c4631ab46d760
 F src/expr.c e1327eb020a68ff7c49382e121ad4b71b3441b2a
 F src/func.c e45cd908b9b723d9b91473d09e12c23f786b3fc2
 F src/hash.c 6a6236b89c8c060c65dabd300a1c8ce7c10edb72
 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
-F src/insert.c a2f5455009904476b43ec5304a181b505235f72f
+F src/insert.c 764300a0bd8074a2174946c0bf8a550bd833397a
 F src/main.c ff7c05ef88fa1374e5540ce20173ae8e1836f8a4
 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
 F src/os.c 091a89297bf80927cde146cd1dbf89c908864f3a
@@ -41,18 +41,18 @@ F src/select.c 74a025cd6887b636fc06a79ff6246c4eb6826ec4
 F src/shell.c 9e9a6eb6bca07f01e6472a603f908a0127ea50ff
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in d3999a9c6374675779058d6cfe5431131618e92b
-F src/sqliteInt.h 62177a08d332148b1d69cd040840aac45ad86a42
+F src/sqliteInt.h 54caf09fbb64b43a060637c46fb7464ea7b6f759
 F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
-F src/tclsqlite.c 79ceb1d0092cca22785cc00a0a596ba0aca6b363
+F src/tclsqlite.c fa646506f02509455c1e4a878d1303bd2d4c3ead
 F src/test1.c a46e9f61915b32787c5d5a05a4b92e4dacc437d9
 F src/test2.c 5fa694d130b3309e3f9c852f0a437750fcb5a006
 F src/test3.c 540fa7fc3cb3732517b779b5f90ad9cc4303d0ab
 F src/threadtest.c 72bce0a284647314847bbea44616ceb056bfb77f
 F src/tokenize.c 62c98842447effe92eba9622bb2f9a2a8a4b97ad
-F src/trigger.c c90a292a4bef25e478fd5deda6d300319be6a023
-F src/update.c f07e6ed2c517c92871e54d3f5886d1cf56121b11
+F src/trigger.c 5ba917fc226b96065108da28186c2efaec53e481
+F src/update.c 881e4c8e7c786545da4fd2d95da19252b2e31137
 F src/util.c c70d5da5357e01b58392faebae3c3620c1d71f14
-F src/vdbe.c 7e7392f2a92187ba1d2351fed0524c2dd607cffb
+F src/vdbe.c 8e567db1f36b2c6dda4719ebe53d565c087a5702
 F src/vdbe.h b7584044223104ba7896a7f87b66daebdd6022ba
 F src/where.c 53959c9d94adaf93b409271815e26eafa6ddd515
 F test/all.test efd958d048c70a3247997c482f0b33561f7759f0
@@ -75,7 +75,7 @@ F test/intpkey.test f3620158fd7963af1306b01047277f10ae91a30b
 F test/ioerr.test 57d9bffaca18b34f9e976f786eadc2591d6efc6a
 F test/join.test 90a620f2a2d015e5139d5a4cde0eeb4cf62523bf
 F test/limit.test 9f26f874bc765df5b3f5c92d26d1b12eac6d4cf9
-F test/lock.test 5079615ba0ef0899c4cbade42ffec291620a2819
+F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473
 F test/main.test c66b564554b770ee7fdbf6a66c0cd90329bc2c85
 F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd
 F test/memleak.test b4f59aa44488793b00feff2011d77d0f05b22468
@@ -100,7 +100,7 @@ F test/sort.test 876b76c5a837af5bead713146c7c65f85e84fbf5
 F test/subselect.test f0fea8cf9f386d416d64d152e3c65f9116d0f50f
 F test/table.test 10508e5e53fb7971b9fa6acb29d85748e545745c
 F test/tableapi.test 3c80421a889e1d106df16e5800fa787f0d2914a6
-F test/tclsqlite.test 6f4b9760681c7dbca52a18d0ab46a1679cdc79b9
+F test/tclsqlite.test 2441ab135e5af85110326b3e3b057e7257c144e1
 F test/temptable.test 03b7bdb7d6ce2c658ad20c94b037652c6cad34e0
 F test/tester.tcl 6f603d90881bd835ea27c568a7fecaa57dce91cc
 F test/trans.test 10b53c77e2cc4ad9529c15fdcb390b8d5722ea65
@@ -149,7 +149,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P ef7116751ddc4e82228c115b0a332ffb47a22ae5
-R 8189584121ea08912ee4948047822dc1
+P 6cb80ae10af60863cc25c22a6442ba1d43b7409c
+R 780c4a4a4908db085bbda24c5386e9ab
 U drh
-Z 5104f4a49d2a5667b7c13a5b97f926e5
+Z 662e185948fcdefe24022119237f420c
index ff635bc915e709ded465c450575a96ef1b6cb55c..ef575427d75f50d8f0705cd3decb48cb5c3d4ec3 100644 (file)
@@ -1 +1 @@
-6cb80ae10af60863cc25c22a6442ba1d43b7409c
\ No newline at end of file
+3f253afe15d4f7392555f340a41d780d1248087f
\ No newline at end of file
index 4c1102d8fcb4a8434bcb4ccb4f206fed0c7da34a..39ddd8b6b24cd1f12c8ebd402802753f6af57f63 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.111 2002/08/31 18:53:06 drh Exp $
+** $Id: build.c,v 1.112 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -398,7 +398,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
   ** now.
   */
   if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
-    sqliteBeginWriteOperation(pParse, 0);
+    sqliteBeginWriteOperation(pParse, 0, isTemp);
     if( !isTemp ){
       sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
       sqliteVdbeAddOp(v, OP_SetCookie, 0, 1);
@@ -1105,7 +1105,7 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
     };
     Index *pIdx;
     Trigger *pTrigger;
-    sqliteBeginWriteOperation(pParse, 0);
+    sqliteBeginWriteOperation(pParse, 0, pTable->isTemp);
     sqliteOpenMasterTable(v, pTable->isTemp);
     /* Drop all triggers associated with the table being dropped */
     pTrigger = pTable->pTrigger;
@@ -1537,7 +1537,7 @@ void sqliteCreateIndex(
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto exit_create_index;
     if( pTable!=0 ){
-      sqliteBeginWriteOperation(pParse, 0);
+      sqliteBeginWriteOperation(pParse, 0, isTemp);
       sqliteOpenMasterTable(v, isTemp);
     }
     sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
@@ -1643,7 +1643,7 @@ void sqliteDropIndex(Parse *pParse, Token *pName){
     int base;
     Table *pTab = pIndex->pTable;
 
-    sqliteBeginWriteOperation(pParse, 0);
+    sqliteBeginWriteOperation(pParse, 0, pTab->isTemp);
     sqliteOpenMasterTable(v, pTab->isTemp);
     base = sqliteVdbeAddOpList(v, ArraySize(dropIndex), dropIndex);
     sqliteVdbeChangeP3(v, base+1, pIndex->zName, 0);
@@ -1824,7 +1824,7 @@ void sqliteCopy(
   v = sqliteGetVdbe(pParse);
   if( v ){
     int openOp;
-    sqliteBeginWriteOperation(pParse, 1);
+    sqliteBeginWriteOperation(pParse, 1, pTab->isTemp);
     addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
     sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
     sqliteVdbeDequoteP3(v, addr);
@@ -1910,7 +1910,7 @@ void sqliteBeginTransaction(Parse *pParse, int onError){
        "within a transaction", 0);
     return;
   }
-  sqliteBeginWriteOperation(pParse, 0);
+  sqliteBeginWriteOperation(pParse, 0, 0);
   db->flags |= SQLITE_InTrans;
   db->onError = onError;
 }
@@ -1969,16 +1969,23 @@ void sqliteRollbackTransaction(Parse *pParse){
 ** rollback the whole transaction.  For operations where all constraints
 ** can be checked before any changes are made to the database, it is never
 ** necessary to undo a write and the checkpoint should not be set.
+**
+** The tempOnly flag indicates that only temporary tables will be changed
+** during this write operation.  The primary database table is not
+** write-locked.  Only the temporary database file gets a write lock.
+** Other processes can continue to read or write the primary database file.
 */
-void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint){
+void sqliteBeginWriteOperation(Parse *pParse, int setCheckpoint, int tempOnly){
   Vdbe *v;
   v = sqliteGetVdbe(pParse);
   if( v==0 ) return;
   if( pParse->trigStack ) return; /* if this is in a trigger */
   if( (pParse->db->flags & SQLITE_InTrans)==0 ){
-    sqliteVdbeAddOp(v, OP_Transaction, 0, 0);
-    sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
-    pParse->schemaVerified = 1;
+    sqliteVdbeAddOp(v, OP_Transaction, tempOnly, 0);
+    if( !tempOnly ){
+      sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
+      pParse->schemaVerified = 1;
+    }
   }else if( setCheckpoint ){
     sqliteVdbeAddOp(v, OP_Checkpoint, 0, 0);
   }
@@ -2081,7 +2088,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       int addr;
       int size = atoi(zRight);
       if( size<0 ) size = -size;
-      sqliteBeginWriteOperation(pParse, 0);
+      sqliteBeginWriteOperation(pParse, 0, 0);
       sqliteVdbeAddOp(v, OP_Integer, size, 0);
       sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
       addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
@@ -2172,7 +2179,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
       int addr;
       int size = db->cache_size;
       if( size<0 ) size = -size;
-      sqliteBeginWriteOperation(pParse, 0);
+      sqliteBeginWriteOperation(pParse, 0, 0);
       sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
       sqliteVdbeAddOp(v, OP_Dup, 0, 0);
       addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
index 4998fc55cec3fe2b7b546eaa415f57e51b39879a..55b5e60c835f000199b064280553c3361338a871 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.41 2002/07/19 18:52:41 drh Exp $
+** $Id: delete.c,v 1.42 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -150,7 +150,8 @@ void sqliteDeleteFrom(
   if( v==0 ){
     goto delete_from_cleanup;
   }
-  sqliteBeginWriteOperation(pParse, row_triggers_exist);
+  sqliteBeginWriteOperation(pParse, row_triggers_exist,
+       !row_triggers_exist && pTab->isTemp);
 
   /* Initialize the counter of the number of rows deleted, if
   ** we are counting rows.
index fc2d5cccdbd753d2267d67c0074ace404a990536..5cf44e7074cface02724d860d414c05f22cb660b 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.66 2002/08/28 03:00:58 drh Exp $
+** $Id: insert.c,v 1.67 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -160,7 +160,8 @@ void sqliteInsert(
   */
   v = sqliteGetVdbe(pParse);
   if( v==0 ) goto insert_cleanup;
-  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist);
+  sqliteBeginWriteOperation(pParse, pSelect || row_triggers_exist,
+         !row_triggers_exist && pTab->isTemp);
 
   /* if there are row triggers, allocate a temp table for new.* references. */
   if( row_triggers_exist ){
index 6b40c87684a58a342da544f55811db28381a8929..63b39f9d43025ce21bd20479abbbe1d6dddf8585 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.145 2002/08/31 18:53:07 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.146 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -977,7 +977,7 @@ void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);
 void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*);
 void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
 void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
-void sqliteBeginWriteOperation(Parse*, int);
+void sqliteBeginWriteOperation(Parse*, int, int);
 void sqliteEndWriteOperation(Parse*);
 Expr *sqliteExprDup(Expr*);
 void sqliteTokenCopy(Token*, Token*);
index 8fe2ab908f2e3b8519412a1ebc326a3f043460ce..9037bdac6652c6f4162dd62bd2d6fd2182a12a72 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** A TCL Interface to SQLite
 **
-** $Id: tclsqlite.c,v 1.41 2002/09/03 19:43:24 drh Exp $
+** $Id: tclsqlite.c,v 1.42 2002/09/14 13:47:32 drh Exp $
 */
 #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
 
 # define UTF_TRANSLATION_NEEDED 1
 #endif
 
+/*
+** New SQL functions can be created as TCL scripts.  Each such function
+** is described by an instance of the following structure.
+*/
+typedef struct SqlFunc SqlFunc;
+struct SqlFunc {
+  Tcl_Interp *interp;   /* The TCL interpret to execute the function */
+  char *zScript;        /* The script to be run */
+  SqlFunc *pNext;       /* Next function on the list of them all */
+};
+
 /*
 ** There is one instance of this structure for each SQLite database
 ** that has been opened by the SQLite TCL interface.
@@ -40,6 +51,7 @@ struct SqliteDb {
   sqlite *db;           /* The "real" database structure */
   Tcl_Interp *interp;   /* The interpreter used for this database */
   char *zBusy;          /* The busy callback routine */
+  SqlFunc *pFunc;       /* List of SQL functions */
 };
 
 /*
@@ -239,6 +251,11 @@ static int DbEvalCallback2(
 static void DbDeleteCmd(void *db){
   SqliteDb *pDb = (SqliteDb*)db;
   sqlite_close(pDb->db);
+  while( pDb->pFunc ){
+    SqlFunc *pFunc = pDb->pFunc;
+    pDb->pFunc = pFunc->pNext;
+    Tcl_Free((char*)pFunc);
+  }
   if( pDb->zBusy ){
     Tcl_Free(pDb->zBusy);
   }
@@ -270,6 +287,29 @@ static int DbBusyHandler(void *cd, const char *zTable, int nTries){
   return 1;
 }
 
+/*
+** This routine is called to evaluate an SQL function implemented
+** using TCL script.
+*/
+static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){
+  SqlFunc *p = sqlite_user_data(context);
+  Tcl_DString cmd;
+  int i;
+  int rc;
+
+  Tcl_DStringInit(&cmd);
+  Tcl_DStringAppend(&cmd, p->zScript, -1);
+  for(i=0; i<argc; i++){
+    Tcl_DStringAppendElement(&cmd, argv[i] ? argv[i] : "");
+  }
+  rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
+  if( rc ){
+    sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1); 
+  }else{
+    sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
+  }
+}
+
 /*
 ** The "sqlite" command below creates a new Tcl command for each
 ** connection it opens to an SQLite database.  This routine is invoked
@@ -288,13 +328,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   int choice;
   static const char *DB_strs[] = {
     "busy",               "changes",           "close",
-    "complete",           "eval",              "last_insert_rowid",
-    "open_aux_file",      "timeout",           0
+    "complete",           "eval",              "function",
+    "last_insert_rowid",  "open_aux_file",     "timeout",
+    0                    
   };
   enum DB_enum {
     DB_BUSY,              DB_CHANGES,          DB_CLOSE,
-    DB_COMPLETE,          DB_EVAL,             DB_LAST_INSERT_ROWID,
-    DB_OPEN_AUX_FILE,     DB_TIMEOUT,          
+    DB_COMPLETE,          DB_EVAL,             DB_FUNCTION,
+    DB_LAST_INSERT_ROWID, DB_OPEN_AUX_FILE,    DB_TIMEOUT,
   };
 
   if( objc<2 ){
@@ -468,6 +509,34 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
     return rc;
   }
 
+  /*
+  **     $db function NAME SCRIPT
+  **
+  ** Create a new SQL function called NAME.  Whenever that function is
+  ** called, invoke SCRIPT to evaluate the function.
+  */
+  case DB_FUNCTION: {
+    SqlFunc *pFunc;
+    char *zName;
+    char *zScript;
+    int nScript;
+    if( objc!=4 ){
+      Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
+      return TCL_ERROR;
+    }
+    zName = Tcl_GetStringFromObj(objv[2], 0);
+    zScript = Tcl_GetStringFromObj(objv[3], &nScript);
+    pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
+    if( pFunc==0 ) return TCL_ERROR;
+    pFunc->interp = interp;
+    pFunc->pNext = pDb->pFunc;
+    pFunc->zScript = (char*)&pFunc[1];
+    strcpy(pFunc->zScript, zScript);
+    sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc);
+    sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
+    break;
+  }
+
   /*
   **     $db last_insert_rowid 
   **
index 8cbf1fbf659b7092b972cb0607b28870c578b509..222d09de0d5bbe80127a01042fd57e7b45642a70 100644 (file)
@@ -143,7 +143,7 @@ void sqliteCreateTrigger(
     /* Make an entry in the sqlite_master table */
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto trigger_cleanup;
-    sqliteBeginWriteOperation(pParse, 0);
+    sqliteBeginWriteOperation(pParse, 0, 0);
     sqliteOpenMasterTable(v, tab->isTemp);
     addr = sqliteVdbeAddOpList(v, ArraySize(insertTrig), insertTrig);
     sqliteVdbeChangeP3(v, addr, tab->isTemp ? TEMP_MASTER_NAME : MASTER_NAME,
@@ -386,7 +386,7 @@ void sqliteDropTrigger(Parse *pParse, Token *pName, int nested){
       { OP_Next,       0, ADDR(3),  0}, /* 7 */
     };
 
-    sqliteBeginWriteOperation(pParse, 0);
+    sqliteBeginWriteOperation(pParse, 0, 0);
     sqliteOpenMasterTable(v, pTable->isTemp);
     base = sqliteVdbeAddOpList(v,  ArraySize(dropTrigger), dropTrigger);
     sqliteVdbeChangeP3(v, base+1, zName, 0);
@@ -674,7 +674,7 @@ void sqliteViewTriggers(
 
   v = sqliteGetVdbe(pParse);
   assert(v);
-  sqliteBeginWriteOperation(pParse, 1);
+  sqliteBeginWriteOperation(pParse, 1, 0);
 
   /* Allocate temp tables */
   oldIdx = pParse->nTab++;
index 5407544c36455ce760b50e1a559275381145608b..ce26346543c747de289c7cebca134918a3b958bc 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.49 2002/07/21 23:09:55 danielk1977 Exp $
+** $Id: update.c,v 1.50 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -186,7 +186,7 @@ void sqliteUpdate(
   */
   v = sqliteGetVdbe(pParse);
   if( v==0 ) goto update_cleanup;
-  sqliteBeginWriteOperation(pParse, 1);
+  sqliteBeginWriteOperation(pParse, 1, !row_triggers_exist && pTab->isTemp);
 
   /* Begin the database scan
   */
index 6f5d3c062dc894d1e9c9637c5226c4a02c806d0d..a76bfb44229b5008369b5d4d16771d742fe424ea 100644 (file)
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.177 2002/09/08 17:23:43 drh Exp $
+** $Id: vdbe.c,v 1.178 2002/09/14 13:47:32 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1336,6 +1336,7 @@ int sqliteVdbeExec(
   unsigned uniqueCnt = 0;     /* Used by OP_MakeRecord when P2!=0 */
   int errorAction = OE_Abort; /* Recovery action to do in case of an error */
   int undoTransOnError = 0;   /* If error, either ROLLBACK or COMMIT */
+  int inTempTrans = 0;        /* True if temp database is transactioned */
   char zBuf[100];             /* Space to sprintf() an integer */
   int returnStack[100];     /* Return address stack for OP_Gosub & OP_Return */
   int returnDepth = 0;      /* Next unused element in returnStack[] */
@@ -2919,12 +2920,17 @@ case OP_Checkpoint: {
   break;
 }
 
-/* Opcode: Transaction * * *
+/* Opcode: Transaction P1 * *
 **
 ** Begin a transaction.  The transaction ends when a Commit or Rollback
 ** opcode is encountered.  Depending on the ON CONFLICT setting, the
 ** transaction might also be rolled back if an error is encountered.
 **
+** If P1 is true, then the transaction is started on the temporary
+** tables of the database only.  The main database file is not write
+** locked and other processes can continue to read the main database
+** file.
+**
 ** A write lock is obtained on the database file when a transaction is
 ** started.  No other process can read or write the file while the
 ** transaction is underway.  Starting a transaction also creates a
@@ -2933,13 +2939,14 @@ case OP_Checkpoint: {
 */
 case OP_Transaction: {
   int busy = 0;
-  if( db->pBeTemp ){
+  if( db->pBeTemp && !inTempTrans ){
     rc = sqliteBtreeBeginTrans(db->pBeTemp);
     if( rc!=SQLITE_OK ){
       goto abort_due_to_error;
     }
+    inTempTrans = 1;
   }
-  do{
+  if( pOp->p1==0 ) do{
     rc = sqliteBtreeBeginTrans(pBt);
     switch( rc ){
       case SQLITE_BUSY: {
@@ -2954,6 +2961,7 @@ case OP_Transaction: {
         /* Fall thru into the next case */
       }
       case SQLITE_OK: {
+        inTempTrans = 0;
         busy = 0;
         break;
       }
@@ -2976,7 +2984,7 @@ case OP_Transaction: {
 */
 case OP_Commit: {
   if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
-    rc = sqliteBtreeCommit(pBt);
+    rc = inTempTrans ? SQLITE_OK : sqliteBtreeCommit(pBt);
   }
   if( rc==SQLITE_OK ){
     sqliteCommitInternalChanges(db);
@@ -2985,6 +2993,7 @@ case OP_Commit: {
     sqliteBtreeRollback(pBt);
     sqliteRollbackInternalChanges(db);
   }
+  inTempTrans = 0;
   break;
 }
 
index f51c9fbdc5fae1c62727cb4019781b9101ae54dc..ca715fffff75d6198f71ff35b8c2f492807f3ae7 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is database locks.
 #
-# $Id: lock.test,v 1.17 2002/08/29 23:59:50 drh Exp $
+# $Id: lock.test,v 1.18 2002/09/14 13:47:33 drh Exp $
 
 
 set testdir [file dirname $argv0]
@@ -270,7 +270,62 @@ do_test lock-4.3 {
   set rc [catch {db2 eval {SELECT * FROM t1}} msg]
   lappend rc $msg $::callback_value
 } {1 {database is locked} {1 2 3 4 5}}
+execsql {ROLLBACK}
 
+# When one thread is writing, other threads cannot read.  Except if the
+# writing thread is writing to its temporary tables, the other threads
+# can still read.
+#
+proc tx_exec {sql} {
+  db2 eval $sql
+}
+do_test lock-5.1 {
+  execsql {
+    SELECT * FROM t1
+  }
+} {2 1}
+do_test lock-5.2 {
+  db function tx_exec tx_exec
+  catchsql {
+    INSERT INTO t1(a,b) SELECT 3, tx_exec('SELECT y FROM t2 LIMIT 1');
+  }
+} {1 {database is locked}}
+do_test lock-5.3 {
+  execsql {
+    CREATE TEMP TABLE t3(x);
+    SELECT * FROM t3;
+  }
+} {}
+do_test lock-5.4 {
+  catchsql {
+    INSERT INTO t3 SELECT tx_exec('SELECT y FROM t2 LIMIT 1');
+  }
+} {0 {}}
+do_test lock-5.5 {
+  execsql {
+    SELECT * FROM t3;
+  }
+} {8}
+do_test lock-5.6 {
+  catchsql {
+    UPDATE t1 SET a=tx_exec('SELECT x FROM t2');
+  }
+} {1 {database is locked}}
+do_test lock-5.7 {
+  execsql {
+    SELECT * FROM t1;
+  }
+} {2 1}
+do_test lock-5.8 {
+  catchsql {
+    UPDATE t3 SET x=tx_exec('SELECT x FROM t2');
+  }
+} {0 {}}
+do_test lock-5.9 {
+  execsql {
+    SELECT * FROM t3;
+  }
+} {9}
 
 do_test lock-999.1 {
   rename db2 {}
index e4844ae8f7cca9864b0db5cd9d7f1065b99c11b2..88041859f4958b96fd0da852bbe6aef56bde4bb0 100644 (file)
@@ -15,7 +15,7 @@
 # interface is pretty well tested.  This file contains some addition
 # tests for fringe issues that the main test suite does not cover.
 #
-# $Id: tclsqlite.test,v 1.7 2002/06/25 19:31:18 drh Exp $
+# $Id: tclsqlite.test,v 1.8 2002/09/14 13:47:33 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -29,7 +29,7 @@ do_test tcl-1.1 {
 do_test tcl-1.2 {
   set v [catch {db bogus} msg]
   lappend v $msg
-} {1 {bad option "bogus": must be busy, changes, close, complete, eval, last_insert_rowid, open_aux_file, or timeout}}
+} {1 {bad option "bogus": must be busy, changes, close, complete, eval, function, last_insert_rowid, open_aux_file, or timeout}}
 do_test tcl-1.3 {
   execsql {CREATE TABLE t1(a int, b int)}
   execsql {INSERT INTO t1 VALUES(10,20)}