Start all transactions and verify all schema cookies near the beginning of
of each vdbe program. (CVS 1543) FossilOrigin-Name: 1086196460e261718e78512d77e25dde021a117d
This commit is contained in:
parent
b3e043463d
commit
80242055e5
28
manifest
28
manifest
@ -1,5 +1,5 @@
|
||||
C Do\snot\srequire\sa\sRESERVED\slock\swhen\stransitioning\sfrom\sSHARED\sto\sEXCLUSIVE.\s(CVS\s1542)
|
||||
D 2004-06-08T00:47:47
|
||||
C Start\sall\stransactions\sand\sverify\sall\sschema\scookies\snear\sthe\sbeginning\sof\nof\seach\svdbe\sprogram.\s(CVS\s1543)
|
||||
D 2004-06-09T00:48:12
|
||||
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@ -27,7 +27,7 @@ F src/attach.c e76e4590ec5dd389e5646b171881b5243a6ef391
|
||||
F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79
|
||||
F src/btree.c edb38affc2e83f4299e49104cfe14e6570d8bd32
|
||||
F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa
|
||||
F src/build.c 83303494ccad0ed1cea24f73c7db1f2669820ccd
|
||||
F src/build.c f720a2538af6b39a0edc9f62fad3a8c809d455b5
|
||||
F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2
|
||||
F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d
|
||||
F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37
|
||||
@ -49,14 +49,14 @@ F src/os_win.c a13b85a0d4889e3d0b254ed2a61354acddc59fc4
|
||||
F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c
|
||||
F src/pager.c 3fddd1e5b3e449b19e4f762ab1f1d10786d56d28
|
||||
F src/pager.h 0c7b5ac45c69e690c45d160d03bdc8fbd2d4657b
|
||||
F src/parse.y 27c1ce09f9d309be91f9e537df2fb00892990af4
|
||||
F src/pragma.c 54b4d67fa81fd38b911aa3325348dcae9ceac5a4
|
||||
F src/parse.y 19972fbaa3440f511da36eae1d1fe536fe2c7805
|
||||
F src/pragma.c 9328a31c22615758077e8ded1126affe8f5e7fbe
|
||||
F src/printf.c 63b15f1ea9fe3daa066bb7430fd20d4a2d717dc8
|
||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||
F src/select.c 0ac0adeb2ae15255ac4399d9ee1b0d25a266a676
|
||||
F src/shell.c ca519519dcbbc582f6d88f7d0e7583b857fd3469
|
||||
F src/sqlite.h.in 577974e9a1b85815ccddfb5b858695b62000f595
|
||||
F src/sqliteInt.h 845d2a3ffdb9a9050a1b55044d4856227b649b84
|
||||
F src/sqliteInt.h 472033b41fe76cf0a9c39dda410cedbadeb61b03
|
||||
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
|
||||
F src/tclsqlite.c c4d549ad9f5941288247759ead89d9632254fdc3
|
||||
F src/test1.c 416a37411f2ca7947e6509c5b6ddc6dd86a1204e
|
||||
@ -65,20 +65,20 @@ F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da
|
||||
F src/test4.c a921a69821fd30209589228e64f94e9f715b6fe2
|
||||
F src/test5.c 44178ce85c3afd2004ab4eeb5cfd7487116ce366
|
||||
F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b
|
||||
F src/trigger.c 532daca4972bbf1165bdeecf48d9949eee8c24c0
|
||||
F src/trigger.c 2c28bf37f21e1ca2fc39cd88db8dbe3ad6ac5419
|
||||
F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573
|
||||
F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab
|
||||
F src/util.c 8b3680271111bcdf5b395916b08b9a6684e0e73d
|
||||
F src/vacuum.c b921eb778842592e1fb48a9d4cef7e861103878f
|
||||
F src/vdbe.c 392c6b02c525ea12dff403ba4ceb42b0afcb42f5
|
||||
F src/vdbe.c 3ffa1effb57f861131f1abc6d4f14db81fad2ade
|
||||
F src/vdbe.h 46f74444a213129bc4b5ce40124dd8ed613b0cde
|
||||
F src/vdbeInt.h ab592f23ed5a1913f9a506bd7b76c5e39377942a
|
||||
F src/vdbeapi.c 4ac95766b0515538037a7aec172ed26142f97cf9
|
||||
F src/vdbeaux.c cd1be846336f039442503991fa2aba70f1708554
|
||||
F src/vdbeaux.c ab8c99fd5c94ff366f0db3801eb7a1d3f4026e23
|
||||
F src/vdbemem.c 5d029d83bc60eaf9c45837fcbc0b03348ec95d7a
|
||||
F src/where.c 444a7c3a8b1eb7bba072e489af628555d21d92a4
|
||||
F src/where.c ded00b92dcee77ebe358ff48f5ef05ee8e8ff163
|
||||
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
|
||||
F test/attach.test 1635022d7e1d95dc92fe381cc62f9bf25cb29d73
|
||||
F test/attach.test aed659e52635662bcd5069599aaca823533edf5a
|
||||
F test/attach2.test 2185dce04ef9ceb7b2d3df7d17fb2c3817028dea
|
||||
F test/attach3.test 8259ab833b5dcdf4acd75d9653f42f703ce2e013
|
||||
F test/auth.test 95809b8f6a9bec18b94d28cafd03fe27d2f8a9e9
|
||||
@ -215,7 +215,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248
|
||||
F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075
|
||||
F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9
|
||||
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
|
||||
P 97aa54bb70715934e0af082d51b9b0f6bb847e8e
|
||||
R b382950b985a7f7c010fa51e63195e87
|
||||
P 4dfdea7373f3471d17498da3d6c3aaf926a72d4b
|
||||
R 6bf109928e5c77863915e3d9ce0daa3e
|
||||
U drh
|
||||
Z 979bdbef9456a09bba11f45e5a0188cd
|
||||
Z 588abfea4494baa41bec5420972c8c24
|
||||
|
@ -1 +1 @@
|
||||
4dfdea7373f3471d17498da3d6c3aaf926a72d4b
|
||||
1086196460e261718e78512d77e25dde021a117d
|
94
src/build.c
94
src/build.c
@ -23,7 +23,7 @@
|
||||
** ROLLBACK
|
||||
** PRAGMA
|
||||
**
|
||||
** $Id: build.c,v 1.209 2004/06/08 00:02:33 danielk1977 Exp $
|
||||
** $Id: build.c,v 1.210 2004/06/09 00:48:12 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -58,22 +58,44 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){
|
||||
|
||||
/*
|
||||
** This routine is called after a single SQL statement has been
|
||||
** parsed and we want to execute the VDBE code to implement
|
||||
** that statement. Prior action routines should have already
|
||||
** constructed VDBE code to do the work of the SQL statement.
|
||||
** This routine just has to execute the VDBE code.
|
||||
** parsed and a VDBE program to execute that statement has been
|
||||
** prepared. This routine puts the finishing touches on the
|
||||
** VDBE program and resets the pParse structure for the next
|
||||
** parse.
|
||||
**
|
||||
** Note that if an error occurred, it might be the case that
|
||||
** no VDBE code was generated.
|
||||
*/
|
||||
void sqlite3Exec(Parse *pParse){
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
void sqlite3FinishCoding(Parse *pParse){
|
||||
sqlite *db;
|
||||
Vdbe *v;
|
||||
|
||||
if( v==0 && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
}
|
||||
if( sqlite3_malloc_failed ) return;
|
||||
|
||||
/* Begin by generating some termination code at the end of the
|
||||
** vdbe program
|
||||
*/
|
||||
db = pParse->db;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
|
||||
if( pParse->cookieMask!=0 ){
|
||||
u32 mask;
|
||||
int iDb;
|
||||
sqlite3VdbeChangeP2(v, pParse->cookieGoto, sqlite3VdbeCurrentAddr(v));
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||
if( iDb!=1 ){
|
||||
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]);
|
||||
}
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto+1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the VDBE program ready for execution
|
||||
*/
|
||||
if( v && pParse->nErr==0 ){
|
||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||
sqlite3VdbeTrace(v, trace);
|
||||
@ -88,6 +110,7 @@ void sqlite3Exec(Parse *pParse){
|
||||
pParse->nSet = 0;
|
||||
pParse->nAgg = 0;
|
||||
pParse->nVar = 0;
|
||||
pParse->cookieMask = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2249,19 +2272,41 @@ void sqlite3RollbackTransaction(Parse *pParse){
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that will verify the schema cookie for all
|
||||
** named database files.
|
||||
** Generate VDBE code that will verify the schema cookie and start
|
||||
** a read-transaction for all named database files.
|
||||
**
|
||||
** It is important that all schema cookies be verified and all
|
||||
** read transactions be started before anything else happens in
|
||||
** the VDBE program. But this routine can be called after much other
|
||||
** code has been generated. So here is what we do:
|
||||
**
|
||||
** The first time this routine is called, we code an OP_Gosub that
|
||||
** will jump to a subroutine at the end of the program. Then we
|
||||
** record every database that needs its schema verified in the
|
||||
** pParse->cookieMask field. Later, after all other code has been
|
||||
** generated, the subroutine that does the cookie verifications and
|
||||
** starts the transactions will be coded and the OP_Gosub P2 value
|
||||
** will be made to point to that subroutine. The generation of the
|
||||
** cookie verification subroutine code happens in sqlite3FinishCoding().
|
||||
*/
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
sqlite *db;
|
||||
Vdbe *v;
|
||||
int mask;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return; /* This only happens if there was a prior error */
|
||||
db = pParse->db;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 );
|
||||
if( iDb!=1 && (iDb>63 || !(pParse->cookieMask & ((u64)1<<iDb))) ){
|
||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
|
||||
pParse->cookieMask |= ((u64)1<<iDb);
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<32 );
|
||||
if( pParse->cookieMask==0 ){
|
||||
pParse->cookieGoto = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
|
||||
}
|
||||
mask = 1<<iDb;
|
||||
if( (pParse->cookieMask & mask)==0 ){
|
||||
pParse->cookieMask |= mask;
|
||||
pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2287,11 +2332,8 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){
|
||||
sqlite *db = pParse->db;
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v==0 ) return;
|
||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, 1);
|
||||
if( (iDb>63 || !(pParse->cookieMask & ((u64)1<<iDb))) ){
|
||||
sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, db->aDb[iDb].schema_cookie);
|
||||
pParse->cookieMask |= ((u64)1<<iDb);
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
pParse->writeMask |= 1<<iDb;
|
||||
if( setStatement ){
|
||||
sqlite3VdbeAddOp(v, OP_Statement, iDb, 0);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
** the parser. Lemon will also generate a header file containing
|
||||
** numeric codes for all of the tokens.
|
||||
**
|
||||
** @(#) $Id: parse.y,v 1.125 2004/05/31 08:55:34 danielk1977 Exp $
|
||||
** @(#) $Id: parse.y,v 1.126 2004/06/09 00:48:13 drh Exp $
|
||||
*/
|
||||
%token_prefix TK_
|
||||
%token_type {Token}
|
||||
@ -69,7 +69,7 @@ cmdlist ::= cmdlist ecmd.
|
||||
cmdlist ::= ecmd.
|
||||
ecmd ::= explain cmdx SEMI.
|
||||
ecmd ::= SEMI.
|
||||
cmdx ::= cmd. { sqlite3Exec(pParse); }
|
||||
cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
|
||||
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
|
||||
explain ::= . { sqlite3BeginParse(pParse, 0); }
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.37 2004/06/07 07:52:18 danielk1977 Exp $
|
||||
** $Id: pragma.c,v 1.38 2004/06/09 00:48:13 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -599,6 +599,8 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
||||
HashElem *x;
|
||||
int cnt = 0;
|
||||
|
||||
sqlite3CodeVerifySchema(pParse, i);
|
||||
|
||||
/* Do an integrity check of the B-Tree
|
||||
*/
|
||||
for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
||||
|
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.271 2004/06/07 07:52:18 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.272 2004/06/09 00:48:13 drh Exp $
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "sqlite3.h"
|
||||
@ -58,8 +58,9 @@
|
||||
/*
|
||||
** The maximum number of attached databases. This must be at least 2
|
||||
** in order to support the main database file (0) and the file used to
|
||||
** hold temporary tables (1). And it must be less than 256 because
|
||||
** an unsigned character is used to stored the database index.
|
||||
** hold temporary tables (1). And it must be less than 32 because
|
||||
** we use a bitmask of databases with a u32 in places (for example
|
||||
** the Parse.cookieMask field).
|
||||
*/
|
||||
#define MAX_ATTACHED 10
|
||||
|
||||
@ -1005,7 +1006,10 @@ struct Parse {
|
||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||
TriggerStack *trigStack; /* Trigger actions being coded */
|
||||
u64 cookieMask; /* Bitmask of schema verified databases */
|
||||
u32 cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
u32 writeMask; /* Start a write transaction on these databases */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1202,7 +1206,7 @@ void sqlite3ErrorMsg(Parse*, const char*, ...);
|
||||
void sqlite3Dequote(char*);
|
||||
int sqlite3KeywordCode(const char*, int);
|
||||
int sqlite3RunParser(Parse*, const char*, char **);
|
||||
void sqlite3Exec(Parse*);
|
||||
void sqlite3FinishCoding(Parse*);
|
||||
Expr *sqlite3Expr(int, Expr*, Expr*, Token*);
|
||||
void sqlite3ExprSpan(Expr*,Token*,Token*);
|
||||
Expr *sqlite3ExprFunction(ExprList*, Token*);
|
||||
|
@ -710,7 +710,6 @@ int sqlite3CodeRowTrigger(
|
||||
){
|
||||
Trigger * pTrigger;
|
||||
TriggerStack * pTriggerStack;
|
||||
u64 cookieMask = pParse->cookieMask;
|
||||
|
||||
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
|
||||
assert(tr_tm == TK_BEFORE || tr_tm == TK_AFTER );
|
||||
@ -781,10 +780,5 @@ int sqlite3CodeRowTrigger(
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
|
||||
pParse->cookieMask = cookieMask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
10
src/vdbe.c
10
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.359 2004/06/06 09:44:05 danielk1977 Exp $
|
||||
** $Id: vdbe.c,v 1.360 2004/06/09 00:48:14 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -2302,11 +2302,11 @@ case OP_AutoCommit: {
|
||||
** started. Index 0 is the main database file and index 1 is the
|
||||
** file used for temporary tables.
|
||||
**
|
||||
** If P2 is non-zero, then a write-transaction is started. A write lock is
|
||||
** If P2 is non-zero, then a write-transaction is started. A RESERVED lock is
|
||||
** obtained on the database file when a write-transaction is started. No
|
||||
** other process can read or write the file while the transaction is
|
||||
** underway. Starting a transaction also creates a rollback journal. A
|
||||
** transaction must be started before any changes can be made to the
|
||||
** other process can start another write transaction while this transaction is
|
||||
** underway. Starting a write transaction also creates a rollback journal. A
|
||||
** write transaction must be started before any changes can be made to the
|
||||
** database.
|
||||
**
|
||||
** If P2 is zero, then a read-lock is obtained on the database file.
|
||||
|
@ -654,7 +654,15 @@ void sqlite3VdbeMakeReady(
|
||||
sqlite3HashInit(&p->agg.hash, SQLITE_HASH_BINARY, 0);
|
||||
p->agg.pSearch = 0;
|
||||
#ifdef MEMORY_DEBUG
|
||||
if( sqlite3OsFileExists("vdbe_explain") ){
|
||||
int i;
|
||||
printf("VDBE Program Listing:\n");
|
||||
for(i=0; i<p->nOp; i++){
|
||||
sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
|
||||
}
|
||||
}
|
||||
if( sqlite3OsFileExists("vdbe_trace") ){
|
||||
printf("VDBE Execution Trace:\n");
|
||||
p->trace = stdout;
|
||||
}
|
||||
#endif
|
||||
|
@ -12,7 +12,7 @@
|
||||
** This module contains C code that generates VDBE code used to process
|
||||
** the WHERE clause of SQL statements.
|
||||
**
|
||||
** $Id: where.c,v 1.101 2004/05/29 11:24:50 danielk1977 Exp $
|
||||
** $Id: where.c,v 1.102 2004/06/09 00:48:15 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -671,6 +671,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|
||||
/* Open all tables in the pTabList and all indices used by those tables.
|
||||
*/
|
||||
sqlite3CodeVerifySchema(pParse, 1); /* Inserts the cookie verifier Goto */
|
||||
for(i=0; i<pTabList->nSrc; i++){
|
||||
Table *pTab;
|
||||
Index *pIx;
|
||||
@ -680,7 +681,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0);
|
||||
sqlite3VdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, pTabList->a[i].iCursor, pTab->nCol);
|
||||
sqlite3CodeVerifySchema(pParse, pTab->iDb);
|
||||
if( pTab->tnum>1 ){
|
||||
sqlite3CodeVerifySchema(pParse, pTab->iDb);
|
||||
}
|
||||
if( (pIx = pWInfo->a[i].pIdx)!=0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0);
|
||||
sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum,
|
||||
|
@ -12,7 +12,7 @@
|
||||
# focus of this script is testing the ATTACH and DETACH commands
|
||||
# and related functionality.
|
||||
#
|
||||
# $Id: attach.test,v 1.22 2004/06/07 01:52:15 drh Exp $
|
||||
# $Id: attach.test,v 1.23 2004/06/09 00:48:15 drh Exp $
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -314,7 +314,8 @@ do_test attach-3.3 {
|
||||
}
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
# Even though main has a transaction, test2.db should not be locked.
|
||||
# Even though 'db' has started a transaction, it should not yet have
|
||||
# a lock on test2.db so 'db2' should be readable.
|
||||
do_test attach-3.4 {
|
||||
execsql BEGIN
|
||||
catchsql {
|
||||
@ -322,7 +323,8 @@ do_test attach-3.4 {
|
||||
} db2;
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
# Reading from db2 should not lock test2.db
|
||||
# Reading from test2.db from db within a transaction should not
|
||||
# prevent test2.db from being read by db2.
|
||||
do_test attach-3.5 {
|
||||
execsql {SELECT * FROM t2}
|
||||
catchsql {
|
||||
@ -330,7 +332,8 @@ do_test attach-3.5 {
|
||||
} db2;
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
# Making a change to db2 causes test2.ddb to become locked.
|
||||
# Making a change to test2.db through db causes test2.db to get
|
||||
# a reserved lock. It should still be accessible through db2.
|
||||
do_test attach-3.6 {
|
||||
execsql {
|
||||
UPDATE t2 SET x=x+1 WHERE x=50;
|
||||
@ -338,30 +341,42 @@ do_test attach-3.6 {
|
||||
catchsql {
|
||||
SELECT * FROM t2;
|
||||
} db2;
|
||||
} {1 {database is locked}}
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
do_test attach-3.7 {
|
||||
execsql ROLLBACK
|
||||
execsql {SELECT * FROM t2} db2
|
||||
} {21 x 22 y}
|
||||
|
||||
# Start transactions on both db and db2. Once again, just because
|
||||
# we make a change to test2.db using db2, only a RESERVED lock is
|
||||
# obtained, so test2.db should still be readable using db.
|
||||
#
|
||||
do_test attach-3.8 {
|
||||
execsql BEGIN
|
||||
execsql BEGIN db2
|
||||
execsql {UPDATE t2 SET x=0 WHERE 0} db2
|
||||
catchsql {SELECT * FROM t2}
|
||||
} {1 {database is locked}}
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
# It is also still accessible from db2.
|
||||
do_test attach-3.9 {
|
||||
catchsql {SELECT * FROM t2} db2
|
||||
} {0 {21 x 22 y}}
|
||||
|
||||
do_test attach-3.10 {
|
||||
execsql {SELECT * FROM t1}
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test attach-3.11 {
|
||||
catchsql {UPDATE t1 SET a=a+1}
|
||||
} {0 {}}
|
||||
do_test attach-3.12 {
|
||||
execsql {SELECT * FROM t1}
|
||||
} {2 2 4 4}
|
||||
|
||||
# db2 has a RESERVED lock on test2.db, so db cannot write to any tables
|
||||
# in test2.db.
|
||||
do_test attach-3.13 {
|
||||
catchsql {UPDATE t2 SET x=x+1 WHERE x=50}
|
||||
} {1 {database is locked}}
|
||||
@ -370,18 +385,18 @@ do_test attach-3.13 {
|
||||
# for a locked database.
|
||||
execsql {ROLLBACK}
|
||||
|
||||
# db is able to reread its schema because db2 still only holds a
|
||||
# reserved lock.
|
||||
do_test attach-3.14 {
|
||||
# Unable to reinitialize the schema tables because the aux database
|
||||
# is still locked.
|
||||
catchsql {SELECT * FROM t1}
|
||||
} {1 {database is locked}}
|
||||
} {0 {1 2 3 4}}
|
||||
do_test attach-3.15 {
|
||||
execsql COMMIT db2
|
||||
execsql {SELECT * FROM t1}
|
||||
} {1 2 3 4}
|
||||
|
||||
#set btree_trace 1
|
||||
#puts stderr "###################"; flush stderr
|
||||
|
||||
# Ticket #323
|
||||
do_test attach-4.1 {
|
||||
execsql {DETACH db2}
|
||||
@ -442,6 +457,14 @@ do_test attach-4.7 {
|
||||
SELECT * FROM main.t4;
|
||||
}
|
||||
} {main.11}
|
||||
|
||||
# This one is tricky. On the UNION ALL select, we have to make sure
|
||||
# the schema for both main and db2 is valid before starting to execute
|
||||
# the first query of the UNION ALL. If we wait to test the validity of
|
||||
# the schema for main until after the first query has run, that test will
|
||||
# fail and the query will abort but we will have already output some
|
||||
# results. When the query is retried, the results will be repeated.
|
||||
#
|
||||
do_test attach-4.8 {
|
||||
execsql {
|
||||
ATTACH DATABASE 'test2.db' AS db2;
|
||||
@ -449,6 +472,7 @@ do_test attach-4.8 {
|
||||
SELECT * FROM db2.t4 UNION ALL SELECT * FROM main.t4;
|
||||
}
|
||||
} {db2.6 db2.13 main.11}
|
||||
|
||||
do_test attach-4.9 {
|
||||
execsql {
|
||||
INSERT INTO main.t3 VALUES(15,16);
|
||||
|
Loading…
Reference in New Issue
Block a user