Do not put a write lock on the main database file when writing to a temporary
table. (CVS 750) FossilOrigin-Name: 3f253afe15d4f7392555f340a41d780d1248087f
This commit is contained in:
parent
41a3bd0a01
commit
cabb081971
30
manifest
30
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
|
||||
|
@ -1 +1 @@
|
||||
6cb80ae10af60863cc25c22a6442ba1d43b7409c
|
||||
3f253afe15d4f7392555f340a41d780d1248087f
|
33
src/build.c
33
src/build.c
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 ){
|
||||
|
@ -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*);
|
||||
|
@ -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 */
|
||||
|
||||
@ -31,6 +31,17 @@
|
||||
# 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
|
||||
**
|
||||
|
@ -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++;
|
||||
|
@ -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
|
||||
*/
|
||||
|
19
src/vdbe.c
19
src/vdbe.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {}
|
||||
|
@ -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)}
|
||||
|
Loading…
x
Reference in New Issue
Block a user