aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordanielk1977 <danielk1977@noemail.net>2006-01-07 13:21:04 +0000
committerdanielk1977 <danielk1977@noemail.net>2006-01-07 13:21:04 +0000
commitc00da105654fb2bd0712acccac3e36b539805d08 (patch)
treebe8fb606d3568c09ec40310e35179152dcd56a03 /src
parent8c0ca7d27c60c5a43dbfeab3c869a45e0e3603b1 (diff)
downloadsqlite-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.c13
-rw-r--r--src/btree.c25
-rw-r--r--src/btree.h3
-rw-r--r--src/build.c106
-rw-r--r--src/delete.c18
-rw-r--r--src/insert.c15
-rw-r--r--src/select.c6
-rw-r--r--src/sqliteInt.h48
-rw-r--r--src/tokenize.c9
-rw-r--r--src/trigger.c4
-rw-r--r--src/update.c8
-rw-r--r--src/vdbe.c34
-rw-r--r--src/where.c6
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 ){