mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
Transactions commit on the last sqlite3_step(), not on sqlite3_finalize().
This allows the sqlite3_step() to return SQLITE_BUSY if the commit is blocked by a lock. Ticket #885. (CVS 1928) FossilOrigin-Name: d1b29156558f1c576002cdb2544dffaa693da39b
This commit is contained in:
29
manifest
29
manifest
@ -1,5 +1,5 @@
|
||||
C Work\saround\sa\sbug\sin\sthe\sBorland\sC++\scompiler.\s\sTicket\s#881.\s(CVS\s1927)
|
||||
D 2004-09-01T16:12:25
|
||||
C Transactions\scommit\son\sthe\slast\ssqlite3_step(),\snot\son\ssqlite3_finalize().\nThis\sallows\sthe\ssqlite3_step()\sto\sreturn\sSQLITE_BUSY\sif\sthe\scommit\sis\nblocked\sby\sa\slock.\s\sTicket\s#885.\s(CVS\s1928)
|
||||
D 2004-09-02T14:57:08
|
||||
F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450
|
||||
F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -40,7 +40,7 @@ F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c fc1ce65a0fe68f226143de9b43c3582164a92aff
|
||||
F src/legacy.c 2f3617c61bcdcd1d776154a9cfebf99facda8ad8
|
||||
F src/main.c b92d44c72298d31e08700b1483ef8827468dac9f
|
||||
F src/main.c c42b3c1c9e0e401a490ed8f8ce789eb7302a9b69
|
||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||
F src/os.h d1780e0db95cad01f213d48da22ab490eb4fd345
|
||||
F src/os_common.h cd7eb025fdab7dc91e0e97bf6310f1648205857f
|
||||
@ -52,7 +52,7 @@ F src/os_unix.c a5625eed7ab071d1715df783f4684945ae538a22
|
||||
F src/os_unix.h f3097815e041e82e24d92505e1ff61ba24172d13
|
||||
F src/os_win.c 9e2887825b1a32f0ceb1b73b93ffe29a112cd86f
|
||||
F src/os_win.h babd4e912967c6b09088cfe38a45e8005a07ba44
|
||||
F src/pager.c 616563dc510993ab67baa54fc6a2ddacc05175ca
|
||||
F src/pager.c ae06c85de0db43f61a7a3e5eacad3fd5615daf59
|
||||
F src/pager.h 67739fe649f33be55dba522ca8a9cc4e42d14f71
|
||||
F src/parse.y 581a2ce014b843506805b2470c02b7865ad034d5
|
||||
F src/pragma.c b39177b96bb5f7354511468c933357ce65a0dd4c
|
||||
@ -75,16 +75,16 @@ F src/update.c bbe126c67529bd699016af2d72bc4ceb8fd41527
|
||||
F src/utf.c 328890099db492dda5620ee5f924e244c6e57ff7
|
||||
F src/util.c d5aaf211543fb6e285654fada50252c857ac78aa
|
||||
F src/vacuum.c 9978a5760c2c430bc5b5e66505a02dad76f25813
|
||||
F src/vdbe.c 28b0ea2a8c534fc39e15e41db0437fcc3b5f2e9b
|
||||
F src/vdbe.c 45f659497b479f001c2f4e8251474aba3975b9f8
|
||||
F src/vdbe.h e081c72cd0f7c19d49b1927460aeefcf0fbc85ac
|
||||
F src/vdbeInt.h aadadddc8cfad6aa5a5445c849f70d881276fe34
|
||||
F src/vdbeInt.h f8df57a9dc272967991f806e612628e0aa57e705
|
||||
F src/vdbeapi.c 854732720c2cfc6ff76b28eef6253ac84a5408bc
|
||||
F src/vdbeaux.c 022c484dba235d2dcbb1faca0f1943702f4232ed
|
||||
F src/vdbeaux.c 77eaaf62b8b3acad4a2ef351e3c44ecffc67faf6
|
||||
F src/vdbemem.c ef9ac7d32acfe4bce5c5b408b1294c8d9e0cdb56
|
||||
F src/where.c a84eee276cd072158224da6b5f30733df2d56027
|
||||
F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c
|
||||
F test/attach.test feb2ce54e78688df4c84553416d5aec3b2a0112e
|
||||
F test/attach2.test 9be9656bc1e929b224861960299920c76d45b14d
|
||||
F test/attach2.test 32ca2c1a5a347a7404219a11f9f84739a63d2582
|
||||
F test/attach3.test 6d060986ff004ebb89e1876a331d96c6bb62269e
|
||||
F test/auth.test e74b015545f608c06d5b84d17acdf7146eb818af
|
||||
F test/bigfile.test 62722ac4b420dfbcdceb137b8634e2cf2865fe27
|
||||
@ -97,8 +97,9 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
|
||||
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
|
||||
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
|
||||
F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293
|
||||
F test/capi2.test 78f2c486689fcc80394a24c2cc32725330ab6299
|
||||
F test/capi3.test e2d47b59c1ca5be2e5986fb77f716a7fdd228e25
|
||||
F test/capi2.test 53e3f399074d5654f26d55b32ccaca7b5b619933
|
||||
F test/capi3.test 9258ca75fc98d89477015dcd70aa3d2757b142b8
|
||||
F test/capi3b.test 458044d8c250c129ddfd77c6265a6923bc008b5e
|
||||
F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03
|
||||
F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b
|
||||
F test/collate3.test e60b428e07ec945492ba90ff1c895902ee3a8a50
|
||||
@ -153,7 +154,7 @@ F test/pager3.test 16f546293bb751b8151dc17df613fca938bbec8b
|
||||
F test/pragma.test 66a66b7f3b273b93325c9a5794acb418f52fdcbf
|
||||
F test/printf.test 5a30fb0d736148fca64cb1b7ed0390be7414e024
|
||||
F test/progress.test 76c722f090b1ccb575e7e4e203a71608c5763beb x
|
||||
F test/quick.test 2e9af7203555ea894af654adf0794157434928fb
|
||||
F test/quick.test 212a9cd4c40c72c7c4780fef1c2fbe5d1cb34ce6
|
||||
F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62
|
||||
F test/rollback.test 4097328d44510277244ef4fa51b22b2f11d7ef4c
|
||||
F test/rowid.test b3d059f5c8d8874fa1c31030e0636f67405d20ea
|
||||
@ -246,7 +247,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25
|
||||
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P 9c411c3c8dde2061c98513a413ef58c5c2de45af
|
||||
R 54ca511e52d24afac36ea482ae4bc8ec
|
||||
P 18af6ba580a5ad50a20955bfe2ebce8e30b1d39e
|
||||
R 8124409cd5ad134f1cc0a6f820ab9a66
|
||||
U drh
|
||||
Z 888aa66dde2c6dec44c62c3082b0fba4
|
||||
Z 68ff020543a01eac2435ebdc5d559c02
|
||||
|
@ -1 +1 @@
|
||||
18af6ba580a5ad50a20955bfe2ebce8e30b1d39e
|
||||
d1b29156558f1c576002cdb2544dffaa693da39b
|
@ -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.256 2004/08/29 20:08:59 drh Exp $
|
||||
** $Id: main.c,v 1.257 2004/09/02 14:57:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -521,7 +521,6 @@ void sqlite3RollbackAll(sqlite *db){
|
||||
}
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
/* sqlite3RollbackInternalChanges(db); */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -987,7 +986,7 @@ int sqlite3_prepare(
|
||||
** Make a copy of that part of the SQL string since zSQL is const
|
||||
** and we must pass a zero terminated string to the trace function
|
||||
** The copy is unnecessary if the tail pointer is pointing at the
|
||||
** beginnig or end of the SQL string.
|
||||
** beginning or end of the SQL string.
|
||||
*/
|
||||
if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){
|
||||
char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql);
|
||||
|
@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.161 2004/08/30 16:52:18 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.162 2004/09/02 14:57:08 drh Exp $
|
||||
*/
|
||||
#include "os.h" /* Must be first to enable large file support */
|
||||
#include "sqliteInt.h"
|
||||
@ -2798,10 +2798,7 @@ int sqlite3pager_commit(Pager *pPager){
|
||||
/* Jump here if anything goes wrong during the commit process.
|
||||
*/
|
||||
commit_abort:
|
||||
rc = sqlite3pager_rollback(pPager);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = SQLITE_FULL;
|
||||
}
|
||||
sqlite3pager_rollback(pPager);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
45
src/vdbe.c
45
src/vdbe.c
@ -43,7 +43,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.412 2004/08/31 13:45:12 drh Exp $
|
||||
** $Id: vdbe.c,v 1.413 2004/09/02 14:57:09 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -621,12 +621,12 @@ case OP_Return: {
|
||||
** Exit immediately. All open cursors, Lists, Sorts, etc are closed
|
||||
** automatically.
|
||||
**
|
||||
** P1 is the result code returned by sqlite3_exec(). For a normal
|
||||
** halt, this should be SQLITE_OK (0). For errors, it can be some
|
||||
** other value. If P1!=0 then P2 will determine whether or not to
|
||||
** rollback the current transaction. Do not rollback if P2==OE_Fail.
|
||||
** Do the rollback if P2==OE_Rollback. If P2==OE_Abort, then back
|
||||
** out all changes that have occurred during this execution of the
|
||||
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
|
||||
** or sqlite3_finalize(). For a normal halt, this should be SQLITE_OK (0).
|
||||
** For errors, it can be some other value. If P1!=0 then P2 will determine
|
||||
** whether or not to rollback the current transaction. Do not rollback
|
||||
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback. If P2==OE_Abort,
|
||||
** then back out all changes that have occurred during this execution of the
|
||||
** VDBE, but do not rollback the transaction.
|
||||
**
|
||||
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
|
||||
@ -634,17 +634,21 @@ case OP_Return: {
|
||||
** is the same as executing Halt.
|
||||
*/
|
||||
case OP_Halt: {
|
||||
p->magic = VDBE_MAGIC_HALT;
|
||||
p->pTos = pTos;
|
||||
if( pOp->p1!=SQLITE_OK ){
|
||||
p->rc = pOp->p1;
|
||||
p->pc = pc;
|
||||
p->errorAction = pOp->p2;
|
||||
if( pOp->p3 ){
|
||||
sqlite3SetString(&p->zErrMsg, pOp->p3, (char*)0);
|
||||
return SQLITE_ERROR;
|
||||
}else{
|
||||
p->rc = SQLITE_OK;
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
rc = sqlite3VdbeHalt(p);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
p->rc = SQLITE_BUSY;
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
}
|
||||
return p->rc ? SQLITE_ERROR : SQLITE_DONE;
|
||||
}
|
||||
|
||||
/* Opcode: Integer P1 * P3
|
||||
@ -2118,6 +2122,8 @@ case OP_Statement: {
|
||||
** Set the database auto-commit flag to P1 (1 or 0). If P2 is true, roll
|
||||
** back any currently active btree transactions. If there are any active
|
||||
** VMs (apart from this one), then the COMMIT or ROLLBACK statement fails.
|
||||
**
|
||||
** This instruction causes the VM to halt.
|
||||
*/
|
||||
case OP_AutoCommit: {
|
||||
u8 i = pOp->p1;
|
||||
@ -2126,7 +2132,7 @@ case OP_AutoCommit: {
|
||||
assert( i==1 || i==0 );
|
||||
assert( i==1 || rollback==0 );
|
||||
|
||||
assert( db->activeVdbeCnt>0 );
|
||||
assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */
|
||||
|
||||
if( db->activeVdbeCnt>1 && i && !db->autoCommit ){
|
||||
/* If this instruction implements a COMMIT or ROLLBACK, other VMs are
|
||||
@ -2138,10 +2144,17 @@ case OP_AutoCommit: {
|
||||
rc = SQLITE_ERROR;
|
||||
}else if( i!=db->autoCommit ){
|
||||
db->autoCommit = i;
|
||||
p->autoCommitOn |= i;
|
||||
if( pOp->p2 ){
|
||||
assert( i==1 );
|
||||
sqlite3RollbackAll(db);
|
||||
}else if( sqlite3VdbeHalt(p)==SQLITE_BUSY ){
|
||||
p->pTos = pTos;
|
||||
p->pc = pc;
|
||||
db->autoCommit = 1-i;
|
||||
p->rc = SQLITE_BUSY;
|
||||
return SQLITE_BUSY;
|
||||
}
|
||||
return SQLITE_DONE;
|
||||
}else{
|
||||
sqlite3SetString(&p->zErrMsg,
|
||||
(!i)?"cannot start a transaction within a transaction":(
|
||||
@ -4451,7 +4464,7 @@ vdbe_halt:
|
||||
}else{
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
p->magic = VDBE_MAGIC_HALT;
|
||||
sqlite3VdbeHalt(p);
|
||||
p->pTos = pTos;
|
||||
return rc;
|
||||
|
||||
|
@ -338,7 +338,6 @@ struct Vdbe {
|
||||
char *zErrMsg; /* Error message written here */
|
||||
u8 resOnStack; /* True if there are result values on the stack */
|
||||
u8 explain; /* True if EXPLAIN present on SQL command */
|
||||
u8 autoCommitOn; /* True if autocommit got turned on by this program */
|
||||
u8 changeCntOn; /* True to update the change-counter */
|
||||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
@ -379,6 +378,7 @@ int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
|
||||
int sqlite3VdbeIdxRowidLen(int,const u8*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
int sqlite3VdbeList(Vdbe*);
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
int sqlite3VdbeChangeEncoding(Mem *, int);
|
||||
int sqlite3VdbeMemCopy(Mem*, const Mem*);
|
||||
void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int);
|
||||
|
128
src/vdbeaux.c
128
src/vdbeaux.c
@ -543,6 +543,9 @@ void sqlite3VdbePrintSql(Vdbe *p){
|
||||
** as allocating stack space and initializing the program counter.
|
||||
** After the VDBE has be prepped, it can be executed by one or more
|
||||
** calls to sqlite3VdbeExec().
|
||||
**
|
||||
** This is the only way to move a VDBE from VDBE_MAGIC_INIT to
|
||||
** VDBE_MAGIC_RUN.
|
||||
*/
|
||||
void sqlite3VdbeMakeReady(
|
||||
Vdbe *p, /* The VDBE */
|
||||
@ -938,7 +941,11 @@ static int vdbeCommit(sqlite *db){
|
||||
|
||||
/* If there are any write-transactions at all, invoke the commit hook */
|
||||
if( needXcommit && db->xCommitCallback ){
|
||||
if( db->xCommitCallback(db->pCommitArg) ){
|
||||
int rc;
|
||||
sqlite3SafetyOff(db);
|
||||
rc = db->xCommitCallback(db->pCommitArg);
|
||||
sqlite3SafetyOn(db);
|
||||
if( rc ){
|
||||
return SQLITE_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
@ -1124,6 +1131,8 @@ static void abortOtherActiveVdbes(Vdbe *pVdbe){
|
||||
** This routine checks that the sqlite3.activeVdbeCnt count variable
|
||||
** matches the number of vdbe's in the list sqlite3.pVdbe that are
|
||||
** currently active. An assertion fails if the two counts do not match.
|
||||
** This is an internal self-check only - it is not an essential processing
|
||||
** step.
|
||||
**
|
||||
** This is a no-op if NDEBUG is defined.
|
||||
*/
|
||||
@ -1131,15 +1140,13 @@ static void abortOtherActiveVdbes(Vdbe *pVdbe){
|
||||
static void checkActiveVdbeCnt(sqlite *db){
|
||||
Vdbe *p;
|
||||
int cnt = 0;
|
||||
|
||||
p = db->pVdbe;
|
||||
while( p ){
|
||||
if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
|
||||
if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){
|
||||
cnt++;
|
||||
}
|
||||
p = p->pNext;
|
||||
}
|
||||
|
||||
assert( cnt==db->activeVdbeCnt );
|
||||
}
|
||||
#else
|
||||
@ -1147,61 +1154,42 @@ static void checkActiveVdbeCnt(sqlite *db){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Clean up a VDBE after execution but do not delete the VDBE just yet.
|
||||
** Write any error messages into *pzErrMsg. Return the result code.
|
||||
** This routine is called the when a VDBE tries to halt. If the VDBE
|
||||
** has made changes and is in autocommit mode, then commit those
|
||||
** changes. If a rollback is needed, then do the rollback.
|
||||
**
|
||||
** After this routine is run, the VDBE should be ready to be executed
|
||||
** again.
|
||||
** This routine is the only way to move the state of a VM from
|
||||
** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT.
|
||||
**
|
||||
** Return an error code. If the commit could not complete because of
|
||||
** lock contention, return SQLITE_BUSY. If SQLITE_BUSY is returned, it
|
||||
** means the close did not happen and needs to be repeated.
|
||||
*/
|
||||
int sqlite3VdbeReset(Vdbe *p){
|
||||
int sqlite3VdbeHalt(Vdbe *p){
|
||||
sqlite *db = p->db;
|
||||
int i;
|
||||
int (*xFunc)(Btree *pBt) = 0; /* Function to call on each btree backend */
|
||||
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0 ,0);
|
||||
return SQLITE_MISUSE;
|
||||
if( p->magic!=VDBE_MAGIC_RUN ){
|
||||
/* Already halted. Nothing to do. */
|
||||
assert( p->magic==VDBE_MAGIC_HALT );
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( p->zErrMsg ){
|
||||
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg, 0);
|
||||
sqliteFree(p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
}else{
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
}
|
||||
Cleanup(p);
|
||||
|
||||
/* What is done now depends on the exit status of the vdbe, the value of
|
||||
** the sqlite.autoCommit flag and whether or not there are any other
|
||||
** queries in progress. A transaction or statement transaction may need
|
||||
** to be committed or rolled back on each open database file.
|
||||
*/
|
||||
closeAllCursors(p);
|
||||
checkActiveVdbeCnt(db);
|
||||
if( db->autoCommit && db->activeVdbeCnt==1 ){
|
||||
if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
|
||||
/* The auto-commit flag is true, there are no other active queries
|
||||
** using this handle and the vdbe program was successful or hit an
|
||||
** 'OR FAIL' constraint. This means a commit is required, which is
|
||||
** handled a little differently from the other options.
|
||||
** 'OR FAIL' constraint. This means a commit is required.
|
||||
*/
|
||||
p->rc = vdbeCommit(db);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
if( p->rc==SQLITE_BUSY && p->autoCommitOn ){
|
||||
/* If we just now have turned autocommit on (meaning we just have
|
||||
** finished executing a COMMIT command) but the commit fails due
|
||||
** to lock contention, autocommit back off. This gives the user
|
||||
** the opportunity to try again after the lock that was preventing
|
||||
** the commit has cleared. */
|
||||
db->autoCommit = 0;
|
||||
}else{
|
||||
/* If the command just executed was not a COMMIT command, then
|
||||
** rollback whatever the results of that command were */
|
||||
int rc = vdbeCommit(db);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
p->rc = rc;
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
xFunc = sqlite3BtreeRollback;
|
||||
}
|
||||
@ -1216,7 +1204,6 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
abortOtherActiveVdbes(p);
|
||||
}
|
||||
}
|
||||
p->autoCommitOn = 0;
|
||||
|
||||
/* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,
|
||||
** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on
|
||||
@ -1242,16 +1229,65 @@ int sqlite3VdbeReset(Vdbe *p){
|
||||
p->nChange = 0;
|
||||
}
|
||||
|
||||
/* Rollback or commit any schema changes that occurred. */
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
sqlite3RollbackInternalChanges(db);
|
||||
}else if( db->flags & SQLITE_InternChanges ){
|
||||
sqlite3CommitInternalChanges(db);
|
||||
}
|
||||
|
||||
if( (p->magic==VDBE_MAGIC_RUN && p->pc>=0) || p->magic==VDBE_MAGIC_HALT ){
|
||||
/* We have successfully halted and closed the VM. Record this fact. */
|
||||
if( p->pc>=0 ){
|
||||
db->activeVdbeCnt--;
|
||||
}
|
||||
p->magic = VDBE_MAGIC_HALT;
|
||||
checkActiveVdbeCnt(db);
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clean up a VDBE after execution but do not delete the VDBE just yet.
|
||||
** Write any error messages into *pzErrMsg. Return the result code.
|
||||
**
|
||||
** After this routine is run, the VDBE should be ready to be executed
|
||||
** again.
|
||||
**
|
||||
** To look at it another way, this routine resets the state of the
|
||||
** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to
|
||||
** VDBE_MAGIC_INIT.
|
||||
*/
|
||||
int sqlite3VdbeReset(Vdbe *p){
|
||||
if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
|
||||
sqlite3Error(p->db, SQLITE_MISUSE, 0 ,0);
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
/* If the VM did not run to completion or if it encountered an
|
||||
** error, then it might not have been halted properly. So halt
|
||||
** it now.
|
||||
*/
|
||||
sqlite3VdbeHalt(p);
|
||||
|
||||
/* Transfer the error code and error message from the VDBE into the
|
||||
** main database structure.
|
||||
*/
|
||||
if( p->zErrMsg ){
|
||||
sqlite3Error(p->db, p->rc, "%s", p->zErrMsg, 0);
|
||||
sqliteFree(p->zErrMsg);
|
||||
p->zErrMsg = 0;
|
||||
}else if( p->rc ){
|
||||
sqlite3Error(p->db, p->rc, 0);
|
||||
}else{
|
||||
sqlite3Error(p->db, SQLITE_OK, 0);
|
||||
}
|
||||
|
||||
/* Reclaim all memory used by the VDBE
|
||||
*/
|
||||
Cleanup(p);
|
||||
|
||||
/* Save profiling information from this VDBE run.
|
||||
*/
|
||||
assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );
|
||||
#ifdef VDBE_PROFILE
|
||||
{
|
||||
|
@ -12,7 +12,7 @@
|
||||
# focus of this script is testing the ATTACH and DETACH commands
|
||||
# and related functionality.
|
||||
#
|
||||
# $Id: attach2.test,v 1.25 2004/08/18 16:05:20 drh Exp $
|
||||
# $Id: attach2.test,v 1.26 2004/09/02 14:57:09 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -263,7 +263,6 @@ do_test attach2-4.9 {
|
||||
lock_status 4.9.1 db {main shared temp closed file2 shared}
|
||||
lock_status 4.9.2 db2 {main reserved temp closed file2 reserved}
|
||||
|
||||
btree_breakpoint
|
||||
do_test attach2-4.10 {
|
||||
# We cannot commit db2 while db is holding a read-lock
|
||||
catchsql {COMMIT} db2
|
||||
@ -273,7 +272,6 @@ lock_status 4.10.1 db {main shared temp closed file2 shared}
|
||||
lock_status 4.10.2 db2 {main pending temp closed file2 reserved}
|
||||
|
||||
set sqlite_os_trace 0
|
||||
btree_breakpoint
|
||||
do_test attach2-4.11 {
|
||||
# db is able to commit.
|
||||
catchsql {COMMIT}
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script testing the callback-free C/C++ API.
|
||||
#
|
||||
# $Id: capi2.test,v 1.18 2004/06/30 06:30:26 danielk1977 Exp $
|
||||
# $Id: capi2.test,v 1.19 2004/09/02 14:57:09 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -203,7 +203,8 @@ do_test capi2-3.10 {
|
||||
|
||||
# Update for v3 - the change has not actually happened until the query is
|
||||
# finalized. Is this going to cause trouble for anyone? Lee Nelson maybe?
|
||||
do_test capi2-3.10b {db changes} {0}
|
||||
# (Later:) The change now happens just before SQLITE_DONE is returned.
|
||||
do_test capi2-3.10b {db changes} {1}
|
||||
do_test capi2-3.11 {
|
||||
sqlite3_finalize $VM
|
||||
} {SQLITE_OK}
|
||||
@ -220,8 +221,9 @@ do_test capi2-3.13 {
|
||||
} {SQLITE_ERROR 0 {} {}}
|
||||
|
||||
# Update for v3: Preparing a statement does not affect the change counter.
|
||||
# (Test result changes from 0 to 1).
|
||||
do_test capi2-3.13b {db changes} {1}
|
||||
# (Test result changes from 0 to 1). (Later:) change counter updates occur
|
||||
# when sqlite3_step returns, not at finalize time.
|
||||
do_test capi2-3.13b {db changes} {0}
|
||||
|
||||
do_test capi2-3.14 {
|
||||
list [sqlite3_finalize $VM] [sqlite3_errmsg $DB]
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this script testing the callback-free C/C++ API.
|
||||
#
|
||||
# $Id: capi3.test,v 1.20 2004/07/22 15:02:26 drh Exp $
|
||||
# $Id: capi3.test,v 1.21 2004/09/02 14:57:09 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -536,7 +536,7 @@ if {![sqlite3 -has-codec]} {
|
||||
btree_close_cursor $::bc
|
||||
btree_commit $::bt
|
||||
btree_close $::bt
|
||||
} {}
|
||||
} {};
|
||||
do_test capi3-8.5 {
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
|
90
test/capi3b.test
Normal file
90
test/capi3b.test
Normal file
@ -0,0 +1,90 @@
|
||||
# 2004 September 2
|
||||
#
|
||||
# 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. The
|
||||
# focus of this script testing the callback-free C/C++ API and in
|
||||
# particular the behavior of sqlite3_step() when trying to commit
|
||||
# with lock contention.
|
||||
#
|
||||
# $Id: capi3b.test,v 1.1 2004/09/02 14:57:09 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
db close
|
||||
set DB [sqlite3 db test.db]
|
||||
set DB2 [sqlite3 db2 test.db]
|
||||
|
||||
# Create some data in the database
|
||||
#
|
||||
do_test capi3b-1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
SELECT * FROM t1
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
# Make sure the second database connection can see the data
|
||||
#
|
||||
do_test capi3b-1.2 {
|
||||
execsql {
|
||||
SELECT * FROM t1
|
||||
} db2
|
||||
} {1 2}
|
||||
|
||||
# First database connection acquires a shared lock
|
||||
#
|
||||
do_test capi3b-1.3 {
|
||||
execsql {
|
||||
BEGIN;
|
||||
SELECT * FROM t1;
|
||||
}
|
||||
} {1 2}
|
||||
|
||||
# Second database connection tries to write. The sqlite3_step()
|
||||
# function returns SQLITE_BUSY because it cannot commit.
|
||||
#
|
||||
do_test capi3b-1.4 {
|
||||
set VM [sqlite3_prepare $DB2 {INSERT INTO t1 VALUES(3)} -1 TAIL]
|
||||
sqlite3_step $VM
|
||||
} SQLITE_BUSY
|
||||
|
||||
# The sqlite3_step call can be repeated multiple times.
|
||||
#
|
||||
do_test capi3b-1.5.1 {
|
||||
sqlite3_step $VM
|
||||
} SQLITE_BUSY
|
||||
do_test capi3b-1.5.2 {
|
||||
sqlite3_step $VM
|
||||
} SQLITE_BUSY
|
||||
|
||||
# The first connection closes its transaction. This allows the second
|
||||
# connections sqlite3_step to succeed.
|
||||
#
|
||||
do_test capi3b-1.6 {
|
||||
execsql COMMIT
|
||||
sqlite3_step $VM
|
||||
} SQLITE_DONE
|
||||
do_test capi3b-1.7 {
|
||||
sqlite3_finalize $VM
|
||||
} SQLITE_OK
|
||||
do_test capi3b-1.8 {
|
||||
execsql {SELECT * FROM t1} db2
|
||||
} {1 2 3}
|
||||
do_test capi3b-1.9 {
|
||||
execsql {SELECT * FROM t1}
|
||||
} {1 2 3}
|
||||
|
||||
catch {db2 close}
|
||||
finish_test
|
@ -10,7 +10,7 @@
|
||||
#***********************************************************************
|
||||
# This file runs all tests.
|
||||
#
|
||||
# $Id: quick.test,v 1.29 2004/08/30 16:52:19 drh Exp $
|
||||
# $Id: quick.test,v 1.30 2004/09/02 14:57:09 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -21,6 +21,10 @@ set ISQUICK 1
|
||||
set EXCLUDE {
|
||||
all.test
|
||||
btree2.test
|
||||
btree3.test
|
||||
btree4.test
|
||||
btree5.test
|
||||
btree6.test
|
||||
corrupt.test
|
||||
crash.test
|
||||
malloc.test
|
||||
|
Reference in New Issue
Block a user