mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Add locks to the in-memory database so that recursive writes will be detected
and rejected. Ticket #436. (CVS 1090) FossilOrigin-Name: 966b1a16f6687df08f8c21787c1c8b1af1d79e1e
This commit is contained in:
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\scompiler\swarnings\sunder\sOpenVMS.\s\sTicket\s#357.\s(CVS\s1088)
|
C Add\slocks\sto\sthe\sin-memory\sdatabase\sso\sthat\srecursive\swrites\swill\sbe\sdetected\nand\srejected.\s\sTicket\s#436.\s(CVS\s1090)
|
||||||
D 2003-08-26T11:41:27
|
D 2003-08-27T22:52:34
|
||||||
F Makefile.in f7e916ae863393827fa6a4cb292e3398096edcf1
|
F Makefile.in f7e916ae863393827fa6a4cb292e3398096edcf1
|
||||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||||
@ -23,7 +23,7 @@ F src/attach.c 9f78b4aaac02a2b09ff108e92cbaee3199e7962a
|
|||||||
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
F src/auth.c c8f50d4507e37779d96ff3c55417bc2b612dfed6
|
||||||
F src/btree.c ba1cc0c71c3d2742b9a9047832335dc7d3656c45
|
F src/btree.c ba1cc0c71c3d2742b9a9047832335dc7d3656c45
|
||||||
F src/btree.h 9b7c09f1e64274d7bb74a57bbfc63778f67b1048
|
F src/btree.h 9b7c09f1e64274d7bb74a57bbfc63778f67b1048
|
||||||
F src/btree_rb.c f30f5cddc4375c05bf361116da1492d9601760ca
|
F src/btree_rb.c 2f7ee4fa951d761c470ffadbf691883717a1efe7
|
||||||
F src/build.c 7cdc95266496f53673a66202477b137d514898cf
|
F src/build.c 7cdc95266496f53673a66202477b137d514898cf
|
||||||
F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73
|
F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73
|
||||||
F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc
|
F src/delete.c 0f81e6799c089487615d38e042a2de4d2d6192bc
|
||||||
@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3
|
|||||||
F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
|
||||||
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
|
||||||
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
|
||||||
P cbe32216966c987902ceb4d85332fc95801dbda2
|
P c95f347cac27732533a2f6fd4ba50bf00eef59f3
|
||||||
R ddd7131f94b88ef749e9dcf2a2026ce5
|
R 002b3717598c8349a2d682847ae9c09b
|
||||||
U drh
|
U drh
|
||||||
Z bc22588721b74c4fdc0bad5666b4494e
|
Z 4b1d0cc8167eef257f9d48654435d622
|
||||||
|
@ -1 +1 @@
|
|||||||
c95f347cac27732533a2f6fd4ba50bf00eef59f3
|
966b1a16f6687df08f8c21787c1c8b1af1d79e1e
|
@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree_rb.c,v 1.14 2003/06/29 18:29:48 drh Exp $
|
** $Id: btree_rb.c,v 1.15 2003/08/27 22:52:34 drh Exp $
|
||||||
**
|
**
|
||||||
** This file implements an in-core database using Red-Black balanced
|
** This file implements an in-core database using Red-Black balanced
|
||||||
** binary trees.
|
** binary trees.
|
||||||
@ -99,7 +99,9 @@ struct RbtCursor {
|
|||||||
BtRbTree *pTree;
|
BtRbTree *pTree;
|
||||||
int iTree; /* Index of pTree in pRbtree */
|
int iTree; /* Index of pTree in pRbtree */
|
||||||
BtRbNode *pNode;
|
BtRbNode *pNode;
|
||||||
|
RbtCursor *pShared; /* List of all cursors on the same Rbtree */
|
||||||
u8 eSkip; /* Determines if next step operation is a no-op */
|
u8 eSkip; /* Determines if next step operation is a no-op */
|
||||||
|
u8 wrFlag; /* True if this cursor is open for writing */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -111,7 +113,8 @@ struct RbtCursor {
|
|||||||
#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
|
#define SKIP_INVALID 3 /* Calls to Next() and Previous() are invalid */
|
||||||
|
|
||||||
struct BtRbTree {
|
struct BtRbTree {
|
||||||
BtRbNode *pHead; /* Head of the tree, or NULL */
|
RbtCursor *pCursors; /* All cursors pointing to this tree */
|
||||||
|
BtRbNode *pHead; /* Head of the tree, or NULL */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BtRbNode {
|
struct BtRbNode {
|
||||||
@ -139,6 +142,33 @@ static int memRbtreeNext(RbtCursor* pCur, int *pRes);
|
|||||||
static int memRbtreeLast(RbtCursor* pCur, int *pRes);
|
static int memRbtreeLast(RbtCursor* pCur, int *pRes);
|
||||||
static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
|
static int memRbtreePrevious(RbtCursor* pCur, int *pRes);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine checks all cursors that point to the same table
|
||||||
|
** as pCur points to. If any of those cursors were opened with
|
||||||
|
** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
|
||||||
|
** cursors point to the same table were opened with wrFlag==1
|
||||||
|
** then this routine returns SQLITE_OK.
|
||||||
|
**
|
||||||
|
** In addition to checking for read-locks (where a read-lock
|
||||||
|
** means a cursor opened with wrFlag==0) this routine also NULLs
|
||||||
|
** out the pNode field of all other cursors.
|
||||||
|
** This is necessary because an insert
|
||||||
|
** or delete might change erase the node out from under
|
||||||
|
** another cursor.
|
||||||
|
*/
|
||||||
|
static int checkReadLocks(RbtCursor *pCur){
|
||||||
|
RbtCursor *p;
|
||||||
|
assert( pCur->wrFlag );
|
||||||
|
for(p=pCur->pTree->pCursors; p; p=p->pShared){
|
||||||
|
if( p!=pCur ){
|
||||||
|
if( p->wrFlag==0 ) return SQLITE_LOCKED;
|
||||||
|
p->pNode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The key-compare function for the red-black trees. Returns as follows:
|
* The key-compare function for the red-black trees. Returns as follows:
|
||||||
*
|
*
|
||||||
@ -636,6 +666,7 @@ static int memRbtreeDropTable(Rbtree* tree, int n)
|
|||||||
memRbtreeClearTable(tree, n);
|
memRbtreeClearTable(tree, n);
|
||||||
pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
|
pTree = sqliteHashInsert(&tree->tblHash, 0, n, 0);
|
||||||
assert(pTree);
|
assert(pTree);
|
||||||
|
assert( pTree->pCursors==0 );
|
||||||
sqliteFree(pTree);
|
sqliteFree(pTree);
|
||||||
|
|
||||||
if( tree->eTransState != TRANS_ROLLBACK ){
|
if( tree->eTransState != TRANS_ROLLBACK ){
|
||||||
@ -668,7 +699,7 @@ static int memRbtreeKeyCompare(RbtCursor* pCur, const void *pKey, int nKey,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
|
* Get a new cursor for table iTable of the supplied Rbtree. The wrFlag
|
||||||
* parameter is ignored, all cursors are capable of write-operations.
|
* parameter indicates that the cursor is open for writing.
|
||||||
*
|
*
|
||||||
* Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
|
* Note that RbtCursor.eSkip and RbtCursor.pNode both initialize to 0.
|
||||||
*/
|
*/
|
||||||
@ -678,12 +709,17 @@ static int memRbtreeCursor(
|
|||||||
int wrFlag,
|
int wrFlag,
|
||||||
RbtCursor **ppCur
|
RbtCursor **ppCur
|
||||||
){
|
){
|
||||||
|
RbtCursor *pCur;
|
||||||
assert(tree);
|
assert(tree);
|
||||||
*ppCur = sqliteMalloc(sizeof(RbtCursor));
|
pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor));
|
||||||
(*ppCur)->pTree = sqliteHashFind(&tree->tblHash, 0, iTable);
|
pCur->pTree = sqliteHashFind(&tree->tblHash, 0, iTable);
|
||||||
(*ppCur)->pRbtree = tree;
|
pCur->pRbtree = tree;
|
||||||
(*ppCur)->iTree = iTable;
|
pCur->iTree = iTable;
|
||||||
(*ppCur)->pOps = &sqliteRbtreeCursorOps;
|
pCur->pOps = &sqliteRbtreeCursorOps;
|
||||||
|
pCur->wrFlag = wrFlag;
|
||||||
|
pCur->pShared = pCur->pTree->pCursors;
|
||||||
|
pCur->pTree->pCursors = pCur;
|
||||||
|
|
||||||
|
|
||||||
assert( (*ppCur)->pTree );
|
assert( (*ppCur)->pTree );
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
@ -711,6 +747,11 @@ static int memRbtreeInsert(
|
|||||||
** not in a transaction */
|
** not in a transaction */
|
||||||
assert( pCur->pRbtree->eTransState != TRANS_NONE );
|
assert( pCur->pRbtree->eTransState != TRANS_NONE );
|
||||||
|
|
||||||
|
/* Make sure some other cursor isn't trying to read this same table */
|
||||||
|
if( checkReadLocks(pCur) ){
|
||||||
|
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
|
||||||
|
}
|
||||||
|
|
||||||
/* Take a copy of the input data now, in case we need it for the
|
/* Take a copy of the input data now, in case we need it for the
|
||||||
* replace case */
|
* replace case */
|
||||||
pData = sqliteMalloc(nData);
|
pData = sqliteMalloc(nData);
|
||||||
@ -869,6 +910,11 @@ static int memRbtreeDelete(RbtCursor* pCur)
|
|||||||
** not in a transaction */
|
** not in a transaction */
|
||||||
assert( pCur->pRbtree->eTransState != TRANS_NONE );
|
assert( pCur->pRbtree->eTransState != TRANS_NONE );
|
||||||
|
|
||||||
|
/* Make sure some other cursor isn't trying to read this same table */
|
||||||
|
if( checkReadLocks(pCur) ){
|
||||||
|
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
|
||||||
|
}
|
||||||
|
|
||||||
pZ = pCur->pNode;
|
pZ = pCur->pNode;
|
||||||
if( !pZ ){
|
if( !pZ ){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
@ -1146,6 +1192,16 @@ static int memRbtreeData(RbtCursor *pCur, int offset, int amt, char *zBuf)
|
|||||||
|
|
||||||
static int memRbtreeCloseCursor(RbtCursor* pCur)
|
static int memRbtreeCloseCursor(RbtCursor* pCur)
|
||||||
{
|
{
|
||||||
|
if( pCur->pTree->pCursors==pCur ){
|
||||||
|
pCur->pTree->pCursors = pCur->pShared;
|
||||||
|
}else{
|
||||||
|
RbtCursor *p = pCur->pTree->pCursors;
|
||||||
|
while( p && p->pShared!=pCur ){ p = p->pShared; }
|
||||||
|
assert( p!=0 );
|
||||||
|
if( p ){
|
||||||
|
p->pShared = pCur->pShared;
|
||||||
|
}
|
||||||
|
}
|
||||||
sqliteFree(pCur);
|
sqliteFree(pCur);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@ -1249,6 +1305,7 @@ static void execute_rollback_list(Rbtree *pRbtree, BtRollbackOp *pList)
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
cur.pRbtree = pRbtree;
|
cur.pRbtree = pRbtree;
|
||||||
|
cur.wrFlag = 1;
|
||||||
while( pList ){
|
while( pList ){
|
||||||
switch( pList->eOp ){
|
switch( pList->eOp ){
|
||||||
case ROLLBACK_INSERT:
|
case ROLLBACK_INSERT:
|
||||||
|
Reference in New Issue
Block a user