diff options
author | danielk1977 <danielk1977@noemail.net> | 2006-01-07 13:21:04 +0000 |
---|---|---|
committer | danielk1977 <danielk1977@noemail.net> | 2006-01-07 13:21:04 +0000 |
commit | c00da105654fb2bd0712acccac3e36b539805d08 (patch) | |
tree | be8fb606d3568c09ec40310e35179152dcd56a03 /src | |
parent | 8c0ca7d27c60c5a43dbfeab3c869a45e0e3603b1 (diff) | |
download | sqlite-c00da105654fb2bd0712acccac3e36b539805d08.tar.gz sqlite-c00da105654fb2bd0712acccac3e36b539805d08.zip |
In shared-cache mode, lock all required tables before beginning to execute the body of the statement program. (CVS 2881)
FossilOrigin-Name: 23b587b05b89727248805e6d9e5141e018cf2152
Diffstat (limited to 'src')
-rw-r--r-- | src/analyze.c | 13 | ||||
-rw-r--r-- | src/btree.c | 25 | ||||
-rw-r--r-- | src/btree.h | 3 | ||||
-rw-r--r-- | src/build.c | 106 | ||||
-rw-r--r-- | src/delete.c | 18 | ||||
-rw-r--r-- | src/insert.c | 15 | ||||
-rw-r--r-- | src/select.c | 6 | ||||
-rw-r--r-- | src/sqliteInt.h | 48 | ||||
-rw-r--r-- | src/tokenize.c | 9 | ||||
-rw-r--r-- | src/trigger.c | 4 | ||||
-rw-r--r-- | src/update.c | 8 | ||||
-rw-r--r-- | src/vdbe.c | 34 | ||||
-rw-r--r-- | src/where.c | 6 |
13 files changed, 227 insertions, 68 deletions
diff --git a/src/analyze.c b/src/analyze.c index 3bcc8add4..4669c733b 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.12 2006/01/05 11:34:33 danielk1977 Exp $ +** @(#) $Id: analyze.c,v 1.13 2006/01/07 13:21:04 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -61,8 +61,14 @@ static void openStatTable( sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); } - /* Open the sqlite_stat1 table for writing. + /* Open the sqlite_stat1 table for writing. Unless it was created + ** by this vdbe program, lock it for writing at the shared-cache level. + ** If this vdbe did create the sqlite_stat1 table, then it must have + ** already obtained a schema-lock, making the write-lock redundant. */ + if( iRootPage>0 ){ + sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); + } sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); @@ -103,6 +109,9 @@ static void analyzeOneTable( } #endif + /* Establish a read-lock on the table at the shared-cache level. */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); + iIdxCur = pParse->nTab; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ /* Open a cursor to the index to be analyzed diff --git a/src/btree.c b/src/btree.c index 9847f72c8..9f0a2e7f5 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.284 2006/01/06 21:52:50 drh Exp $ +** $Id: btree.c,v 1.285 2006/01/07 13:21:04 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -2686,13 +2686,6 @@ int sqlite3BtreeCursor( } } -#ifndef SQLITE_OMIT_SHARED_CACHE - rc = queryTableLock(p, iTable, wrFlag?WRITE_LOCK:READ_LOCK); - if( rc!=SQLITE_OK ){ - return rc; - } -#endif - if( pBt->pPage1==0 ){ rc = lockBtreeWithRetry(p); if( rc!=SQLITE_OK ){ @@ -2715,13 +2708,6 @@ int sqlite3BtreeCursor( goto create_cursor_exception; } - /* Obtain the table-lock on the shared-btree. */ - rc = lockTable(p, iTable, wrFlag?WRITE_LOCK:READ_LOCK); - if( rc!=SQLITE_OK ){ - assert( rc==SQLITE_NOMEM ); - goto create_cursor_exception; - } - /* Now that no other errors can occur, finish filling in the BtCursor ** variables, link the cursor into the BtShared list and set *ppCur (the ** output argument to this function). @@ -6492,6 +6478,15 @@ int sqlite3BtreeSchemaLocked(Btree *p){ return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); } +int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ + u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK); + int rc = queryTableLock(p, iTab, lockType); + if( rc==SQLITE_OK ){ + rc = lockTable(p, iTab, lockType); + } + return rc; +} + #ifndef SQLITE_OMIT_SHARED_CACHE /* ** Enable the shared pager and schema features. diff --git a/src/btree.h b/src/btree.h index 6a65813c9..70bdbd467 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.68 2006/01/06 13:00:30 danielk1977 Exp $ +** @(#) $Id: btree.h,v 1.69 2006/01/07 13:21:04 danielk1977 Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -78,6 +78,7 @@ int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeSync(Btree*, const char *zMaster); void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); int sqlite3BtreeSchemaLocked(Btree *); +int sqlite3BtreeLockTable(Btree *, int, u8); const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetDirname(Btree *); diff --git a/src/build.c b/src/build.c index 528058a59..494972b4b 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.368 2006/01/06 06:33:13 danielk1977 Exp $ +** $Id: build.c,v 1.369 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -36,6 +36,87 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){ pParse->nVar = 0; } +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** The TableLock structure is only used by the sqlite3TableLock() and +** codeTableLocks() functions. +*/ +struct TableLock { + int iDb; + int iTab; + u8 isWriteLock; + const char *zName; +}; + +/* +** Have the compiled statement lock the table with rootpage iTab in database +** iDb at the shared-cache level when executed. The isWriteLock argument +** is zero for a read-lock, or non-zero for a write-lock. +** +** The zName parameter should point to the unqualified table name. This is +** used to provide a more informative error message should the lock fail. +*/ +void sqlite3TableLock( + Parse *pParse, + int iDb, + int iTab, + u8 isWriteLock, + const char *zName +){ + int i; + int nBytes; + TableLock *p; + SqliteTsd *pTsd = sqlite3Tsd(); + + if( 0==pTsd->useSharedData ){ + return; + } + + for(i=0; i<pParse->nTableLock; i++){ + p = &pParse->aTableLock[i]; + if( p->iDb==iDb && p->iTab==iTab ){ + p->isWriteLock = (p->isWriteLock || isWriteLock); + return; + } + } + + nBytes = sizeof(TableLock) * (pParse->nTableLock+1); + sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes); + if( pParse->aTableLock ){ + p = &pParse->aTableLock[pParse->nTableLock++]; + p->iDb = iDb; + p->iTab = iTab; + p->isWriteLock = isWriteLock; + p->zName = zName; + } +} + +/* +** Code an OP_TableLock instruction for each table locked by the +** statement (configured by calls to sqlite3TableLock()). +*/ +static void codeTableLocks(Parse *pParse){ + int i; + Vdbe *pVdbe; + assert( sqlite3Tsd()->useSharedData || pParse->nTableLock==0 ); + + if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ + return; + } + + for(i=0; i<pParse->nTableLock; i++){ + TableLock *p = &pParse->aTableLock[i]; + int p1 = p->iDb; + if( p->isWriteLock ){ + p1 = -1*(p1+1); + } + sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC); + } +} +#else + #define codeTableLocks(x) +#endif + /* ** This routine is called after a single SQL statement has been ** parsed and a VDBE program to execute that statement has been @@ -73,6 +154,7 @@ void sqlite3FinishCoding(Parse *pParse){ ** transaction on each used database and to verify the schema cookie ** on each used database. */ + assert( pParse->cookieGoto>0 || pParse->nTableLock==0 ); if( pParse->cookieGoto>0 ){ u32 mask; int iDb; @@ -82,6 +164,12 @@ void sqlite3FinishCoding(Parse *pParse){ sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } + + /* Once all the cookies have been verified and transactions opened, + ** obtain the required table-locks. This is a no-op unless the + ** shared-cache feature is enabled. + */ + codeTableLocks(pParse); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); } @@ -509,7 +597,9 @@ char *sqlite3NameFromToken(Token *pName){ ** Open the sqlite_master table stored in database number iDb for ** writing. The table is opened using cursor 0. */ -void sqlite3OpenMasterTable(Vdbe *v, int iDb){ +void sqlite3OpenMasterTable(Parse *p, int iDb){ + Vdbe *v = sqlite3GetVdbe(p); + sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb)); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT); sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */ @@ -777,7 +867,7 @@ void sqlite3StartTable( { sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0); } - sqlite3OpenMasterTable(v, iDb); + sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); sqlite3VdbeAddOp(v, OP_Null, 0, 0); @@ -1374,6 +1464,11 @@ void sqlite3EndTable( ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used ** by the new table. + ** + ** A shared-cache write-lock is not required to write to the new table, + ** as a schema-lock must have already been obtained to create it. Since + ** a schema-lock excludes all other database users, the write-lock would + ** be redundant. */ if( pSelect ){ Table *pSelTab; @@ -2052,6 +2147,9 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ return; } + /* Require a write-lock on the table to perform this operation */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); + v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ @@ -2064,7 +2162,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char*)&pIndex->keyInfo, P3_KEYINFO); - sqlite3OpenTableForReading(v, iTab, iDb, pTab); + sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); if( pIndex->onError!=OE_None ){ diff --git a/src/delete.c b/src/delete.c index 9114304ed..9c5cf5175 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** -** $Id: delete.c,v 1.114 2006/01/05 11:34:34 danielk1977 Exp $ +** $Id: delete.c,v 1.115 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -59,15 +59,19 @@ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ /* ** Generate code that will open a table for reading. */ -void sqlite3OpenTableForReading( - Vdbe *v, /* Generate code into this VDBE */ +void sqlite3OpenTable( + Parse *p, /* Generate code into this VDBE */ int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ - Table *pTab /* The table to be opened */ + Table *pTab, /* The table to be opened */ + int opcode /* OP_OpenRead or OP_OpenWrite */ ){ + Vdbe *v = sqlite3GetVdbe(p); + assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); + sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pTab->zName)); - sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); + sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } @@ -208,7 +212,7 @@ void sqlite3DeleteFrom( int endOfLoop = sqlite3VdbeMakeLabel(v); int addr; if( !isView ){ - sqlite3OpenTableForReading(v, iCur, iDb, pTab); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); @@ -276,7 +280,7 @@ void sqlite3DeleteFrom( addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); if( !isView ){ sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3OpenTableForReading(v, iCur, iDb, pTab); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); diff --git a/src/insert.c b/src/insert.c index 64bff8d5c..dea6c6fc1 100644 --- a/src/insert.c +++ b/src/insert.c @@ -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.152 2006/01/05 11:34:34 danielk1977 Exp $ +** $Id: insert.c,v 1.153 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -305,9 +305,7 @@ void sqlite3Insert( int base = sqlite3VdbeCurrentAddr(v); counterRowid = pParse->nMem++; counterMem = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSchema->pSeqTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); + sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13); sqlite3VdbeAddOp(v, OP_Column, iCur, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); @@ -686,9 +684,7 @@ void sqlite3Insert( if( pTab->autoInc ){ int iCur = pParse->nTab; int base = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSchema->pSeqTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); + sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0); sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); @@ -1110,10 +1106,7 @@ void sqlite3OpenTableAndIndices( Index *pIdx; Vdbe *v = sqlite3GetVdbe(pParse); assert( v!=0 ); - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - VdbeComment((v, "# %s", pTab->zName)); - sqlite3VdbeAddOp(v, op, base, pTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); + sqlite3OpenTable(pParse, base, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ assert( pIdx->pSchema==pTab->pSchema ); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); diff --git a/src/select.c b/src/select.c index af19681c5..c1eaec9bf 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.285 2006/01/05 14:22:34 danielk1977 Exp $ +** $Id: select.c,v 1.286 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -2229,6 +2229,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ iCol = pExpr->iColumn; pTab = pSrc->a[0].pTab; + /* If we get to here, it means the query is of the correct form. ** Check to make sure we have an index and make pIdx point to the ** appropriate index. If the min() or max() is on an INTEGER PRIMARY @@ -2266,11 +2267,12 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){ */ iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3CodeVerifySchema(pParse, iDb); + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); base = pSrc->a[0].iCursor; brk = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, brk); if( pSrc->a[0].pSelect==0 ){ - sqlite3OpenTableForReading(v, base, iDb, pTab); + sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead); } if( pIdx==0 ){ sqlite3VdbeAddOp(v, seekOp, base, 0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c3fadd135..e2c618ee1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.452 2006/01/06 15:03:48 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.453 2006/01/07 13:21:04 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -255,7 +255,7 @@ struct BusyHandler { #ifdef SQLITE_MEMDEBUG /* ** The following global variables are used for testing and debugging -** only. They only work if SQLITE_DEBUG is defined. +** only. They only work if SQLITE_MEMDEBUG is defined. */ extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */ extern int sqlite3_nFree; /* Number of sqliteFree() calls */ @@ -264,19 +264,21 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ #define ENTER_MALLOC (\ sqlite3Tsd()->zFile = __FILE__, sqlite3Tsd()->iLine = __LINE__ \ ) -#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x)) -#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x)) -#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y)) -#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x)) -#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y)) +#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x)) +#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x)) +#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y)) +#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x)) +#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y)) +#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y)) #else -#define sqliteMalloc(x) sqlite3Malloc(x) -#define sqliteMallocRaw(x) sqlite3MallocRaw(x) -#define sqliteRealloc(x,y) sqlite3Realloc(x,y) -#define sqliteStrDup(x) sqlite3StrDup(x) -#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) +#define sqliteMalloc(x) sqlite3Malloc(x) +#define sqliteMallocRaw(x) sqlite3MallocRaw(x) +#define sqliteRealloc(x,y) sqlite3Realloc(x,y) +#define sqliteStrDup(x) sqlite3StrDup(x) +#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) +#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y) #endif @@ -359,6 +361,7 @@ typedef struct Select Select; typedef struct SrcList SrcList; typedef struct SqliteTsd SqliteTsd; typedef struct Table Table; +typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TriggerStack TriggerStack; typedef struct TriggerStep TriggerStep; @@ -1224,6 +1227,12 @@ struct Select { ** generate call themselves recursively, the first part of the structure ** is constant but the second part is reset at the beginning and end of ** each recursion. +** +** The nTableLock and aTableLock variables are only used if the shared-cache +** feature is enabled (if sqlite3Tsd()->useSharedData is true). They are +** used to store the set of table-locks required by the statement being +** compiled. Function sqlite3TableLock() is used to add entries to the +** list. */ struct Parse { sqlite3 *db; /* The main database structure */ @@ -1243,6 +1252,10 @@ struct Parse { u32 cookieMask; /* Bitmask of schema verified databases */ int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */ int cookieValue[MAX_ATTACHED+2]; /* Values of cookies to verify */ +#ifndef SQLITE_OMIT_SHARED_CACHE + int nTableLock; /* Number of locks in aTableLock */ + TableLock *aTableLock; /* Required table locks for shared-cache mode */ +#endif /* Above is constant between recursions. Below is reset before and after ** each recursion */ @@ -1505,7 +1518,7 @@ void sqlite3BeginParse(Parse*,int); void sqlite3RollbackInternalChanges(sqlite3*); void sqlite3CommitInternalChanges(sqlite3*); Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*); -void sqlite3OpenMasterTable(Vdbe *v, int); +void sqlite3OpenMasterTable(Parse *, int); void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); @@ -1546,8 +1559,7 @@ void sqlite3SelectDelete(Select*); void sqlite3SelectUnbind(Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); -void sqlite3OpenTableForReading(Vdbe*, int iCur, int iDb, Table*); -void sqlite3OpenTable(Vdbe*, int iCur, Table*, int); +void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**); @@ -1723,6 +1735,12 @@ void sqlite3SchemaFree(void *); DbSchema *sqlite3SchemaGet(Btree *); int sqlite3SchemaToIndex(sqlite3 *db, DbSchema *); +#ifndef SQLITE_OMIT_SHARED_CACHE + void sqlite3TableLock(Parse *, int, int, u8, const char *); +#else + #define sqlite3TableLock(v,w,x,y,z) +#endif + void sqlite3MallocClearFailed(); #ifdef NDEBUG #define sqlite3MallocDisallow() diff --git a/src/tokenize.c b/src/tokenize.c index b3294ef18..6ea3b6878 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.110 2005/12/09 20:02:06 drh Exp $ +** $Id: tokenize.c,v 1.111 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -425,6 +425,13 @@ abort_parse: sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; } +#ifndef SQLITE_OMIT_SHARED_CACHE + if( pParse->nested==0 ){ + sqliteFree(pParse->aTableLock); + pParse->aTableLock = 0; + pParse->nTableLock = 0; + } +#endif sqlite3DeleteTable(pParse->db, pParse->pNewTable); sqlite3DeleteTrigger(pParse->pNewTrigger); sqliteFree(pParse->apVarExpr); diff --git a/src/trigger.c b/src/trigger.c index fcb852d95..b88839335 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -237,7 +237,7 @@ void sqlite3FinishTrigger( v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3OpenMasterTable(v, iDb); + sqlite3OpenMasterTable(pParse, iDb); addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); sqlite3VdbeChangeP3(v, addr+2, pTrig->name, 0); sqlite3VdbeChangeP3(v, addr+3, pTrig->table, 0); @@ -520,7 +520,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ }; sqlite3BeginWriteOperation(pParse, 0, iDb); - sqlite3OpenMasterTable(v, iDb); + sqlite3OpenMasterTable(pParse, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); sqlite3ChangeCookie(db, v, iDb); diff --git a/src/update.c b/src/update.c index fd6edc60f..0a47d1da5 100644 --- a/src/update.c +++ b/src/update.c @@ -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.115 2006/01/05 11:34:34 danielk1977 Exp $ +** $Id: update.c,v 1.116 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -309,7 +309,7 @@ void sqlite3Update( /* Open a cursor and make it point to the record that is ** being updated. */ - sqlite3OpenTableForReading(v, iCur, iDb, pTab); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); @@ -364,9 +364,7 @@ void sqlite3Update( ** action, then we need to open all indices because we might need ** to be deleting some records. */ - sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenWrite); if( onError==OE_Replace ){ openAll = 1; }else{ diff --git a/src/vdbe.c b/src/vdbe.c index 83615842c..bf5ac0991 100644 --- a/src/vdbe.c +++ b/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.513 2006/01/06 14:32:20 drh Exp $ +** $Id: vdbe.c,v 1.514 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -4437,6 +4437,38 @@ case OP_Expire: { /* no-push */ break; } +#ifndef SQLITE_OMIT_SHARED_CACHE +/* Opcode: TableLock P1 P2 P3 +** +** Obtain a lock on a particular table. This instruction is only used when +** the shared-cache feature is enabled. +** +** If P1 is not negative, then it is the index of the index of the database +** in sqlite3.aDb[] and a read-lock is required. If P1 is negative, a +** write-lock is required. In this case the index of the database is the +** absolute value of P1 minus one (iDb = abs(P1) - 1;) and a write-lock is +** required. +** +** P2 contains the root-page of the table to lock. +** +** P3 contains a pointer to the name of the table being locked. This is only +** used to generate an error message if the lock cannot be obtained. +*/ +case OP_TableLock: { /* no-push */ + int p1 = pOp->p1; + u8 isWriteLock = (p1<0); + if( isWriteLock ){ + p1 = (-1*p1)-1; + } + rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); + if( rc==SQLITE_LOCKED ){ + const char *z = (const char *)pOp->p3; + sqlite3SetString(&p->zErrMsg, "database table is locked: ", z, (char*)0); + } + break; +} +#endif /* SHARED_OMIT_SHARED_CACHE */ + /* An other opcode is illegal... */ default: { diff --git a/src/where.c b/src/where.c index 86d3ac3bc..587080bf9 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.190 2006/01/05 11:34:34 danielk1977 Exp $ +** $Id: where.c,v 1.191 2006/01/07 13:21:04 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -1580,7 +1580,9 @@ WhereInfo *sqlite3WhereBegin( iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); if( pTab->isTransient || pTab->pSelect ) continue; if( (pLevel->flags & WHERE_IDX_ONLY)==0 ){ - sqlite3OpenTableForReading(v, pTabItem->iCursor, iDb, pTab); + sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, OP_OpenRead); + }else{ + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } pLevel->iTabCur = pTabItem->iCursor; if( (pIx = pLevel->pIdx)!=0 ){ |