mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
In shared-cache mode, lock all required tables before beginning to execute the body of the statement program. (CVS 2881)
FossilOrigin-Name: 23b587b05b89727248805e6d9e5141e018cf2152
This commit is contained in:
40
manifest
40
manifest
@ -1,5 +1,5 @@
|
||||
C Drop\sthe\smutex\sif\sthe\sTSD\skey\sallocation\sfails.\s\sTicket\s#1585.\s(CVS\s2880)
|
||||
D 2006-01-07T04:06:55
|
||||
C In\sshared-cache\smode,\slock\sall\srequired\stables\sbefore\sbeginning\sto\sexecute\sthe\sbody\sof\sthe\sstatement\sprogram.\s(CVS\s2881)
|
||||
D 2006-01-07T13:21:04
|
||||
F Makefile.in c79fbdaa264c6afcd435f2fb492551de5a8cf80d
|
||||
F Makefile.linux-gcc aee18d8a05546dcf1888bd4547e442008a49a092
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -31,22 +31,22 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.def c413e514217736884254739a105c8c942fdf0c2f
|
||||
F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
|
||||
F src/alter.c e9deb3f4fd7c663a0d1f235d541bc5ea1f2cfa8b
|
||||
F src/analyze.c d821684cdb4d0403e327e4a3440a832e9e54fa3a
|
||||
F src/analyze.c 82e334a1be4bb6961387a4c1441aed90fe9a2d8a
|
||||
F src/attach.c 4a04ffcd17357a7848aa17c12c955d109f533bd0
|
||||
F src/auth.c cdec356a5cd8b217c346f816c5912221537fe87f
|
||||
F src/btree.c dff0ebc0ba1188b5a5586e4108de942549acc6f7
|
||||
F src/btree.h f7ba8e2f9f387cca4978e1495504a0bf556dcbf2
|
||||
F src/build.c 715ac7d49bbfcae5f3fdfd60885397b2133c283b
|
||||
F src/btree.c 902d0d3f5c32b665a2184be5997ae0597bd47d56
|
||||
F src/btree.h 5663c4f43e8521546ccebc8fc95acb013b8f3184
|
||||
F src/build.c 0cf9f744911826ded1c8ee8adbf881ed5a2ef70a
|
||||
F src/callback.c 62066afd516f220575e81b1a1239ab92a2eae252
|
||||
F src/complete.c df1681cef40dec33a286006981845f87b194e7a4
|
||||
F src/date.c 9a1fe548e31a9b14a43b88f711254a968929659d
|
||||
F src/delete.c 2479a8419c76cd4c13f2181d399425ec215ceeb9
|
||||
F src/delete.c 32ba37cced50d26ed996d67dc7d19195e081bbb7
|
||||
F src/experimental.c 50c1e3b34f752f4ac10c36f287db095c2b61766d
|
||||
F src/expr.c ed2a272c7afd63232ca04881159ce2366266e35d
|
||||
F src/func.c 5e4204b2ebe89de5228d78eef9352a0ed253f4c0
|
||||
F src/hash.c 8747cf51d12de46512880dfcf1b68b4e24072863
|
||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||
F src/insert.c d167f9d41932ddaff9162f116e2abc514b0680b6
|
||||
F src/insert.c 66f2e745bd3db551bed9756c7d7df191f7b72ba9
|
||||
F src/legacy.c 59757d857ab95fcbb0ac27692d3201e35f093dd7
|
||||
F src/main.c 8c2d64f1460200d79d7de4605a9489c0506be5fe
|
||||
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
|
||||
@ -66,10 +66,10 @@ F src/pragma.c ae8b135531e7a4d692c60bd909c819d0b3fc588a
|
||||
F src/prepare.c fef89dc92703d345251142af966b60e44a66cfc5
|
||||
F src/printf.c f47a2f4b5387cd2ebb12e9117a1a5d6bd9a2b812
|
||||
F src/random.c d40f8d356cecbd351ccfab6eaedd7ec1b54f5261
|
||||
F src/select.c a60e5c7fad9ce7adc78d9eb32a0a89dd5acd04fb
|
||||
F src/select.c 77bcb71f609ff95247a529acf7dfc1c1ec09154b
|
||||
F src/shell.c 66b073375efbdee19045e7e0cd38b85f9aff71da
|
||||
F src/sqlite.h.in ba3a29daa6a16e054191ccb384a981964e882a1d
|
||||
F src/sqliteInt.h 8e28cfdaf55761f054904c9a5c573e90b96e2433
|
||||
F src/sqliteInt.h 40c3511c05df83c7c1c244d0432baa9497feee4d
|
||||
F src/table.c 486dcfce532685b53b5a2b5da8bba0ded6fb2316
|
||||
F src/tclsqlite.c 42151e6c78502277be77b88c00535d53ce89b917
|
||||
F src/test1.c 1171547fad57a104c716116695fb8c5c7ef43345
|
||||
@ -78,20 +78,20 @@ F src/test3.c 9742aa146eb750cab81c1d5605286c3a0eb88054
|
||||
F src/test4.c a8fd681e139e1c61f22a77d07fc3a99cb28fff3f
|
||||
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
|
||||
F src/test6.c 74d91b487c68154156eded457925d96aa2a3fdbb
|
||||
F src/tokenize.c 7a3a3d3cc734f684a77c4dfd09eb46fcee25394c
|
||||
F src/trigger.c 13c449e61cb2c831e07b9fd7175d0c16dcbb28ac
|
||||
F src/update.c c72e9cbbc0adf8d728c1c39ace03d4adb29b5cfb
|
||||
F src/tokenize.c 10c32e980e3d8db98cfe32e3485a458fda5b3117
|
||||
F src/trigger.c d8e0fe913fcd3819649faf2863cd881ff60ffc2e
|
||||
F src/update.c 29ba0385c8639803cd8e6e616e99096a0bc10443
|
||||
F src/utf.c b7bffac4260177ae7f83c01d025fe0f5ed70ce71
|
||||
F src/util.c 8a3ef3c1b345cdadcee33ce4537c63bb0fda0ed8
|
||||
F src/vacuum.c a7301804d4f849da0ce9d869219c71c6d621c34e
|
||||
F src/vdbe.c 61f37ba6f30c3f1f5c27c9daee517c7e5949c5f9
|
||||
F src/vdbe.c 9ff36ae7887ba918e7c319729038eab59cfeb2b9
|
||||
F src/vdbe.h 8729a4ee16ff9aeab2af9667df3cf300ff978e13
|
||||
F src/vdbeInt.h 9b78ba00cc006bff17e04a54ba3ded9fc7810a10
|
||||
F src/vdbeapi.c 7335569b1bad946ba53892384b4b1534e877b1ee
|
||||
F src/vdbeaux.c a4eea656afebc6161771ddfa7a9c91186a5d7888
|
||||
F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5
|
||||
F src/vdbemem.c deba8d6e3727643924b210a8c531a496c2b8d386
|
||||
F src/where.c 3ec45076e7cce523aad34eaf9bd119237b56942a
|
||||
F src/where.c de22a3a84c595ca1ad206dd19818f65f950e79f8
|
||||
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
|
||||
F test/all.test 90cf64bb655e3d474b0dda04e63ece03e36b0ce2
|
||||
F test/alter.test b94b640063e725d062b2997bd2810ac39195c718
|
||||
@ -220,7 +220,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
|
||||
F test/select5.test 07a90ab3c7e3f0a241a9cdea1d997b2c8a89ff0b
|
||||
F test/select6.test f459a19bdac0501c4d3eb1a4df4b7a76f1bb8ad4
|
||||
F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
|
||||
F test/shared.test 0fc3ba42901d31a9c0c48edbbe6cc61008438b16
|
||||
F test/shared.test a19b3db0d10dcb965ab73b04830f94149f6eb85b
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
F test/subquery.test e6de53332c0301b3cfa34edc3f3cd5fa1e859efd
|
||||
F test/subselect.test 2d13fb7f450db3595adcdd24079a0dd1d2d6abc2
|
||||
@ -335,7 +335,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||
P 22bf1a2ffac503020dfa78d228b561d1cf6f3894
|
||||
R 4f67d90864139abe40a0021c48eb6474
|
||||
U drh
|
||||
Z 8cbffd6d58c70ff076573e18f16ee469
|
||||
P 77ac231c0e21c09c0b612a4e72bcc863f2c95fd3
|
||||
R a3383f6d4bdf9c6fcebb44953df9373f
|
||||
U danielk1977
|
||||
Z 6669b8779258a46a23e7780534ef4f13
|
||||
|
@ -1 +1 @@
|
||||
77ac231c0e21c09c0b612a4e72bcc863f2c95fd3
|
||||
23b587b05b89727248805e6d9e5141e018cf2152
|
@ -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
|
||||
|
25
src/btree.c
25
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.
|
||||
|
@ -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 *);
|
||||
|
106
src/build.c
106
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 ){
|
||||
|
18
src/delete.c
18
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);
|
||||
|
15
src/insert.c
15
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);
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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{
|
||||
|
34
src/vdbe.c
34
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: {
|
||||
|
@ -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 ){
|
||||
|
@ -11,7 +11,7 @@
|
||||
# This file implements regression tests for SQLite library. The
|
||||
# focus of this file is testing the SELECT statement.
|
||||
#
|
||||
# $Id: shared.test,v 1.5 2006/01/06 15:03:48 danielk1977 Exp $
|
||||
# $Id: shared.test,v 1.6 2006/01/07 13:21:04 danielk1977 Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -34,6 +34,7 @@ set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
# shared-4.*: Check that the schema is locked and unlocked correctly.
|
||||
# shared-5.*: Test that creating/dropping schema items works when databases
|
||||
# are attached in different orders to different handles.
|
||||
# shared-6.*: Locking, UNION ALL queries and sub-queries.
|
||||
#
|
||||
|
||||
do_test shared-1.1 {
|
||||
@ -74,7 +75,7 @@ do_test shared-1.4 {
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES(4, 5, 6);
|
||||
} db2
|
||||
} {1 {database table is locked}}
|
||||
} {1 {database table is locked: abc}}
|
||||
do_test shared-1.5 {
|
||||
# Using connection 2 (the one without the open transaction), try to create
|
||||
# a new table. This should fail because of the open read transaction
|
||||
@ -82,7 +83,7 @@ do_test shared-1.5 {
|
||||
catchsql {
|
||||
CREATE TABLE def(d, e, f);
|
||||
} db2
|
||||
} {1 {database table is locked}}
|
||||
} {1 {database table is locked: sqlite_master}}
|
||||
do_test shared-1.6 {
|
||||
# Upgrade connection 1's transaction to a write transaction. Create
|
||||
# a new table - def - and insert a row into it. Because the connection 1
|
||||
@ -134,7 +135,7 @@ do_test shared-2.2 {
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES(1, 2, 3);
|
||||
} db2
|
||||
} {1 {database table is locked}}
|
||||
} {1 {database table is locked: abc}}
|
||||
do_test shared-2.3 {
|
||||
# Turn db's transaction into a write-transaction. db3 should still be
|
||||
# able to read from table def (but will not see the new row). Connection
|
||||
@ -158,7 +159,7 @@ do_test shared-2.3 {
|
||||
] [
|
||||
catchsql { SELECT * FROM def; } db2
|
||||
]
|
||||
} {0 {IV V VI} 1 {database table is locked}}
|
||||
} {0 {IV V VI} 1 {database table is locked: def}}
|
||||
do_test shared-2.4 {
|
||||
# Commit the open transaction on db. db2 still holds a read-transaction.
|
||||
# This should prevent db3 from writing to the database, but not from
|
||||
@ -290,12 +291,12 @@ do_test shared-4.3.2 {
|
||||
catchsql {
|
||||
INSERT INTO abc VALUES('iv', 'v', 'vi');
|
||||
}
|
||||
} {1 {database table is locked}}
|
||||
} {1 {database table is locked: abc}}
|
||||
do_test shared-4.3.3 {
|
||||
catchsql {
|
||||
CREATE TABLE ghi(g, h, i);
|
||||
}
|
||||
} {1 {database table is locked}}
|
||||
} {1 {database table is locked: sqlite_master}}
|
||||
do_test shared-4.3.3 {
|
||||
catchsql {
|
||||
INSERT INTO def VALUES('IV', 'V', 'VI');
|
||||
@ -407,6 +408,60 @@ do_test shared-5.1.2 {
|
||||
} db1
|
||||
} {}
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Tests shared-6.* test that a query obtains all the read-locks it needs
|
||||
# before starting execution of the query. This means that there is no chance
|
||||
# some rows of data will be returned before a lock fails and SQLITE_LOCK
|
||||
# is returned.
|
||||
#
|
||||
do_test shared-6.1.1 {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
} db1
|
||||
execsql {
|
||||
SELECT * FROM t1 UNION ALL SELECT * FROM t2;
|
||||
} db2
|
||||
} {1 2 3 4}
|
||||
do_test shared-6.1.2 {
|
||||
# Establish a write lock on table t2 via connection db2. Then make a
|
||||
# UNION all query using connection db1 that first accesses t1, followed
|
||||
# by t2. If the locks are grabbed at the start of the statement (as
|
||||
# they should be), no rows are returned. If (as was previously the case)
|
||||
# they are grabbed as the tables are accessed, the t1 rows will be
|
||||
# returned before the query fails.
|
||||
#
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t2 VALUES(5, 6);
|
||||
} db2
|
||||
set ret [list]
|
||||
catch {
|
||||
db1 eval {SELECT * FROM t1 UNION ALL SELECT * FROM t2} {
|
||||
lappend ret $a $b
|
||||
}
|
||||
}
|
||||
set ret
|
||||
} {}
|
||||
do_test shared-6.1.3 {
|
||||
execsql {
|
||||
COMMIT;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(7, 8);
|
||||
} db2
|
||||
set ret [list]
|
||||
catch {
|
||||
db1 eval {
|
||||
SELECT (CASE WHEN a>4 THEN (SELECT a FROM t1) ELSE 0 END) AS d FROM t2;
|
||||
} {
|
||||
lappend ret $d
|
||||
}
|
||||
}
|
||||
set ret
|
||||
} {}
|
||||
|
||||
catch {db1 close}
|
||||
catch {db2 close}
|
||||
|
||||
|
Reference in New Issue
Block a user