mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Add function to recover from a malloc() failure. (CVS 2414)
FossilOrigin-Name: 1f9d10d7965c95d1e35f64cf4c3f128adabd41f2
This commit is contained in:
29
manifest
29
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Assorted\sfixes\sto\sthe\shandling\sof\svarious\smalloc()\sfailures.\s(CVS\s2413)
|
C Add\sfunction\sto\srecover\sfrom\sa\smalloc()\sfailure.\s(CVS\s2414)
|
||||||
D 2005-03-21T03:53:38
|
D 2005-03-21T04:04:02
|
||||||
F Makefile.in 5c00d0037104de2a50ac7647a5f12769795957a3
|
F Makefile.in 5c00d0037104de2a50ac7647a5f12769795957a3
|
||||||
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -30,8 +30,8 @@ F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a
|
|||||||
F src/alter.c 8ee27ba2d09f26030c145a780ec8a93cd876d315
|
F src/alter.c 8ee27ba2d09f26030c145a780ec8a93cd876d315
|
||||||
F src/attach.c 3615dbe960cbee4aa5ea300b8a213dad36527b0f
|
F src/attach.c 3615dbe960cbee4aa5ea300b8a213dad36527b0f
|
||||||
F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f
|
F src/auth.c 18c5a0befe20f3a58a41e3ddd78f372faeeefe1f
|
||||||
F src/btree.c 1d9b2179ccac13970c883da6ae3758cc72978bb0
|
F src/btree.c c33c0e6833eb8ac0f0941c1f8e722f7c70dbef57
|
||||||
F src/btree.h 2e2cc923224649337d7217df0dd32b06673ca180
|
F src/btree.h 41a71ce027db9ddee72cb43df2316bbe3a1d92af
|
||||||
F src/build.c 2dc89aa35a0b4aa318ff9eac941f8412fa6db5df
|
F src/build.c 2dc89aa35a0b4aa318ff9eac941f8412fa6db5df
|
||||||
F src/date.c 2134ef4388256e8247405178df8a61bd60dc180a
|
F src/date.c 2134ef4388256e8247405178df8a61bd60dc180a
|
||||||
F src/delete.c d70d54a84695de92efc05b9db7d3684cd21d9094
|
F src/delete.c d70d54a84695de92efc05b9db7d3684cd21d9094
|
||||||
@@ -42,7 +42,7 @@ F src/hash.c 2b1b13f7400e179631c83a1be0c664608c8f021f
|
|||||||
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84
|
||||||
F src/insert.c 34c25c33f51a43644a42cc091ac967b070c6b6d5
|
F src/insert.c 34c25c33f51a43644a42cc091ac967b070c6b6d5
|
||||||
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b
|
||||||
F src/main.c 90cb84bbb85aa89442af41ad4323b136af6527b7
|
F src/main.c 2062faded47289c50cdbc083e00d1aa9a872f1a1
|
||||||
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070
|
||||||
F src/os.h 0c805df3df02b98eb78a7a86756c3cbd4e190939
|
F src/os.h 0c805df3df02b98eb78a7a86756c3cbd4e190939
|
||||||
F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
|
F src/os_common.h 0e7f428ba0a6c40a61bc56c4e96f493231301b73
|
||||||
@@ -52,19 +52,19 @@ F src/os_unix.c fba0167576f09e242afd4c4978e1d2944b1da8b5
|
|||||||
F src/os_unix.h 40b2fd1d02cfa45d6c3dea25316fd019cf9fcb0c
|
F src/os_unix.h 40b2fd1d02cfa45d6c3dea25316fd019cf9fcb0c
|
||||||
F src/os_win.c 2bbbe6fbb010763c3fa79d5e951afca9b138c6b5
|
F src/os_win.c 2bbbe6fbb010763c3fa79d5e951afca9b138c6b5
|
||||||
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||||
F src/pager.c f12044be70383010510d06668e3b6c94f78a4726
|
F src/pager.c d6ba3096969bc306c46b7db9c11cfe0bbedcc9b9
|
||||||
F src/pager.h 70d496f372163abb6340f474288c4bb9ea962cf7
|
F src/pager.h 9a417a1e04737c227ebbba3bdf8597d6dd51513a
|
||||||
F src/parse.y 10c0ace9efce31d5a06e03488a4284b9d97abc56
|
F src/parse.y 10c0ace9efce31d5a06e03488a4284b9d97abc56
|
||||||
F src/pragma.c 4b20dbc0f4b97f412dc511853d3d0c2e0d4adedc
|
F src/pragma.c 4b20dbc0f4b97f412dc511853d3d0c2e0d4adedc
|
||||||
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357
|
||||||
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3
|
||||||
F src/select.c 85695750854188d1eb2d82e0439c99ed6e82645e
|
F src/select.c 85695750854188d1eb2d82e0439c99ed6e82645e
|
||||||
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
|
F src/shell.c 25b3217d7c64e6497225439d261a253a23efff26
|
||||||
F src/sqlite.h.in c85f6bad9ca7de29f505fe886646cfff7df4c55e
|
F src/sqlite.h.in 33e7201f78b3f4aa306d885b69e68fa0f0286368
|
||||||
F src/sqliteInt.h 9b2aa887e79b2ecadc24f0b30363b9ec1e5b51e3
|
F src/sqliteInt.h ecb1592406cf4c684f0ad9ce1bc4fe2a37a61efb
|
||||||
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9
|
||||||
F src/tclsqlite.c 29e56ecdb94c4066dbe6b088d12cc2404bc9597e
|
F src/tclsqlite.c 29e56ecdb94c4066dbe6b088d12cc2404bc9597e
|
||||||
F src/test1.c dd3e4961f3b9b235a68d4af5d77a06eb7be73184
|
F src/test1.c 13d1d2198b3267c8dc6abd22ada4a992c79acefc
|
||||||
F src/test2.c 7f0ef466706ac01414e1136b96e5d8a65cb97545
|
F src/test2.c 7f0ef466706ac01414e1136b96e5d8a65cb97545
|
||||||
F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0
|
F src/test3.c 683e1e3819152ffd35da2f201e507228921148d0
|
||||||
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
|
F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df
|
||||||
@@ -154,6 +154,7 @@ F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f
|
|||||||
F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
|
F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9
|
||||||
F test/main.test febb69416071134dc38b9b1971c0c2e5b0ca3ff8
|
F test/main.test febb69416071134dc38b9b1971c0c2e5b0ca3ff8
|
||||||
F test/malloc.test b7bc72bb1627e09d6003f58de9bcd6e4be839753
|
F test/malloc.test b7bc72bb1627e09d6003f58de9bcd6e4be839753
|
||||||
|
F test/malloc2.test 5375a1cd53caffd56fd06410c5bddc10f6dccded
|
||||||
F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea
|
F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea
|
||||||
F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac
|
F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac
|
||||||
F test/minmax.test 9429a06f1f93acf76fcacafd17160a4392e88526
|
F test/minmax.test 9429a06f1f93acf76fcacafd17160a4392e88526
|
||||||
@@ -172,7 +173,7 @@ F test/pagesize.test 1b826d1608fd86d2303aa895b5586052ad07eba1
|
|||||||
F test/pragma.test 52e4ba758004e2200ff153d09c8b92f19bf940bc
|
F test/pragma.test 52e4ba758004e2200ff153d09c8b92f19bf940bc
|
||||||
F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57
|
F test/printf.test 92ba4c510b4fc61120ffa4a01820446ed917ae57
|
||||||
F test/progress.test 16496001da445e6534afb94562c286708316d82f x
|
F test/progress.test 16496001da445e6534afb94562c286708316d82f x
|
||||||
F test/quick.test 91e5b8ae6663dc9e3e754b271f0384f0cae706e6
|
F test/quick.test 869345bbe45fdad6e3fcc0fc9ec116c0499530c3
|
||||||
F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62
|
F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62
|
||||||
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
F test/reindex.test 38b138abe36bf9a08c791ed44d9f76cd6b97b78b
|
||||||
F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
|
F test/rollback.test 94cd981ee3a627d9f6466f69dcf1f7dbfe695d7a
|
||||||
@@ -277,7 +278,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0
|
||||||
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
|
F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b
|
||||||
P 21012bba176035ff69f860936794a6c2a8eac9df
|
P e7844a01c248e8d9204ea9214bec84c81dc07f32
|
||||||
R 277a3536d0f906527a71bca818fa2ef9
|
R f4236514887458fc97a3ba49da042ffa
|
||||||
U danielk1977
|
U danielk1977
|
||||||
Z c73e8357d1c9dc50a07df66e791e69aa
|
Z 3885f9adee945c24942080cd5fadfb47
|
||||||
|
@@ -1 +1 @@
|
|||||||
e7844a01c248e8d9204ea9214bec84c81dc07f32
|
1f9d10d7965c95d1e35f64cf4c3f128adabd41f2
|
98
src/btree.c
98
src/btree.c
@@ -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.c,v 1.252 2005/03/14 02:01:50 drh Exp $
|
** $Id: btree.c,v 1.253 2005/03/21 04:04:02 danielk1977 Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -2160,12 +2160,11 @@ int sqlite3BtreeCursor(
|
|||||||
goto create_cursor_exception;
|
goto create_cursor_exception;
|
||||||
}
|
}
|
||||||
pCur->pgnoRoot = (Pgno)iTable;
|
pCur->pgnoRoot = (Pgno)iTable;
|
||||||
|
pCur->pPage = 0; /* For exit-handler, in case getAndInitPage() fails. */
|
||||||
if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
|
if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
|
||||||
rc = SQLITE_EMPTY;
|
rc = SQLITE_EMPTY;
|
||||||
pCur->pPage = 0;
|
|
||||||
goto create_cursor_exception;
|
goto create_cursor_exception;
|
||||||
}
|
}
|
||||||
pCur->pPage = 0; /* For exit-handler, in case getAndInitPage() fails. */
|
|
||||||
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0);
|
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
goto create_cursor_exception;
|
goto create_cursor_exception;
|
||||||
@@ -3252,8 +3251,8 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
|||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
ovflPgno = get4byte(pOvfl->aData);
|
ovflPgno = get4byte(pOvfl->aData);
|
||||||
rc = freePage(pOvfl);
|
rc = freePage(pOvfl);
|
||||||
if( rc ) return rc;
|
|
||||||
sqlite3pager_unref(pOvfl->aData);
|
sqlite3pager_unref(pOvfl->aData);
|
||||||
|
if( rc ) return rc;
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -3525,7 +3524,8 @@ static int insertCell(
|
|||||||
end = cellOffset + 2*pPage->nCell + 2;
|
end = cellOffset + 2*pPage->nCell + 2;
|
||||||
ins = cellOffset + 2*i;
|
ins = cellOffset + 2*i;
|
||||||
if( end > top - sz ){
|
if( end > top - sz ){
|
||||||
defragmentPage(pPage);
|
int rc = defragmentPage(pPage);
|
||||||
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
top = get2byte(&data[hdr+5]);
|
top = get2byte(&data[hdr+5]);
|
||||||
assert( end + sz <= top );
|
assert( end + sz <= top );
|
||||||
}
|
}
|
||||||
@@ -4406,7 +4406,7 @@ static int balance_deeper(MemPage *pPage){
|
|||||||
memcpy(&cdata[brk], &data[brk], usableSize-brk);
|
memcpy(&cdata[brk], &data[brk], usableSize-brk);
|
||||||
assert( pChild->isInit==0 );
|
assert( pChild->isInit==0 );
|
||||||
rc = initPage(pChild, pPage);
|
rc = initPage(pChild, pPage);
|
||||||
if( rc ) return rc;
|
if( rc ) goto balancedeeper_out;
|
||||||
memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
|
memcpy(pChild->aOvfl, pPage->aOvfl, pPage->nOverflow*sizeof(pPage->aOvfl[0]));
|
||||||
pChild->nOverflow = pPage->nOverflow;
|
pChild->nOverflow = pPage->nOverflow;
|
||||||
if( pChild->nOverflow ){
|
if( pChild->nOverflow ){
|
||||||
@@ -4420,7 +4420,7 @@ static int balance_deeper(MemPage *pPage){
|
|||||||
if( pBt->autoVacuum ){
|
if( pBt->autoVacuum ){
|
||||||
int i;
|
int i;
|
||||||
rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno);
|
rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno);
|
||||||
if( rc ) return rc;
|
if( rc ) goto balancedeeper_out;
|
||||||
for(i=0; i<pChild->nCell; i++){
|
for(i=0; i<pChild->nCell; i++){
|
||||||
rc = ptrmapPutOvfl(pChild, i);
|
rc = ptrmapPutOvfl(pChild, i);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
@@ -4430,6 +4430,8 @@ static int balance_deeper(MemPage *pPage){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
rc = balance_nonroot(pChild);
|
rc = balance_nonroot(pChild);
|
||||||
|
|
||||||
|
balancedeeper_out:
|
||||||
releasePage(pChild);
|
releasePage(pChild);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -4616,7 +4618,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||||||
unsigned char *pNext;
|
unsigned char *pNext;
|
||||||
int szNext;
|
int szNext;
|
||||||
int notUsed;
|
int notUsed;
|
||||||
unsigned char *tempCell;
|
unsigned char *tempCell = 0;
|
||||||
assert( !pPage->leafData );
|
assert( !pPage->leafData );
|
||||||
getTempCursor(pCur, &leafCur);
|
getTempCursor(pCur, &leafCur);
|
||||||
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
||||||
@@ -4624,26 +4626,34 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||||||
if( rc!=SQLITE_NOMEM ){
|
if( rc!=SQLITE_NOMEM ){
|
||||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
rc = sqlite3pager_write(leafCur.pPage->aData);
|
if( rc==SQLITE_OK ){
|
||||||
if( rc ) return rc;
|
rc = sqlite3pager_write(leafCur.pPage->aData);
|
||||||
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
|
}
|
||||||
pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
|
if( rc==SQLITE_OK ){
|
||||||
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
|
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
|
||||||
pNext = findCell(leafCur.pPage, leafCur.idx);
|
pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno));
|
||||||
szNext = cellSizePtr(leafCur.pPage, pNext);
|
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
|
||||||
assert( MX_CELL_SIZE(pBt)>=szNext+4 );
|
pNext = findCell(leafCur.pPage, leafCur.idx);
|
||||||
tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
|
szNext = cellSizePtr(leafCur.pPage, pNext);
|
||||||
if( tempCell==0 ) return SQLITE_NOMEM;
|
assert( MX_CELL_SIZE(pBt)>=szNext+4 );
|
||||||
rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0);
|
tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
if( tempCell==0 ){
|
||||||
put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
|
rc = SQLITE_NOMEM;
|
||||||
rc = balance(pPage, 0);
|
}
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
rc = insertCell(pPage, pCur->idx, pNext-4, szNext+4, tempCell, 0);
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
put4byte(findOverflowCell(pPage, pCur->idx), pgnoChild);
|
||||||
|
rc = balance(pPage, 0);
|
||||||
|
}
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
dropCell(leafCur.pPage, leafCur.idx, szNext);
|
||||||
|
rc = balance(leafCur.pPage, 0);
|
||||||
|
}
|
||||||
sqliteFree(tempCell);
|
sqliteFree(tempCell);
|
||||||
if( rc ) return rc;
|
|
||||||
dropCell(leafCur.pPage, leafCur.idx, szNext);
|
|
||||||
rc = balance(leafCur.pPage, 0);
|
|
||||||
releaseTempCursor(&leafCur);
|
releaseTempCursor(&leafCur);
|
||||||
}else{
|
}else{
|
||||||
TRACE(("DELETE: table=%d delete from leaf %d\n",
|
TRACE(("DELETE: table=%d delete from leaf %d\n",
|
||||||
@@ -4651,7 +4661,9 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||||||
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
|
dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell));
|
||||||
rc = balance(pPage, 0);
|
rc = balance(pPage, 0);
|
||||||
}
|
}
|
||||||
moveToRoot(pCur);
|
if( rc==SQLITE_OK ){
|
||||||
|
moveToRoot(pCur);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4792,7 +4804,7 @@ static int clearDatabasePage(
|
|||||||
MemPage *pParent, /* Parent page. NULL for the root */
|
MemPage *pParent, /* Parent page. NULL for the root */
|
||||||
int freePageFlag /* Deallocate page if true */
|
int freePageFlag /* Deallocate page if true */
|
||||||
){
|
){
|
||||||
MemPage *pPage;
|
MemPage *pPage = 0;
|
||||||
int rc;
|
int rc;
|
||||||
unsigned char *pCell;
|
unsigned char *pCell;
|
||||||
int i;
|
int i;
|
||||||
@@ -4802,27 +4814,29 @@ static int clearDatabasePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
|
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
|
||||||
if( rc ) return rc;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
rc = sqlite3pager_write(pPage->aData);
|
rc = sqlite3pager_write(pPage->aData);
|
||||||
if( rc ) return rc;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
for(i=0; i<pPage->nCell; i++){
|
for(i=0; i<pPage->nCell; i++){
|
||||||
pCell = findCell(pPage, i);
|
pCell = findCell(pPage, i);
|
||||||
if( !pPage->leaf ){
|
if( !pPage->leaf ){
|
||||||
rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1);
|
rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1);
|
||||||
if( rc ) return rc;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
rc = clearCell(pPage, pCell);
|
rc = clearCell(pPage, pCell);
|
||||||
if( rc ) return rc;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
if( !pPage->leaf ){
|
if( !pPage->leaf ){
|
||||||
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1);
|
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1);
|
||||||
if( rc ) return rc;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
if( freePageFlag ){
|
if( freePageFlag ){
|
||||||
rc = freePage(pPage);
|
rc = freePage(pPage);
|
||||||
}else{
|
}else{
|
||||||
zeroPage(pPage, pPage->aData[0] | PTF_LEAF);
|
zeroPage(pPage, pPage->aData[0] | PTF_LEAF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleardatabasepage_out:
|
||||||
releasePage(pPage);
|
releasePage(pPage);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -4896,7 +4910,10 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){
|
|||||||
rc = getPage(pBt, (Pgno)iTable, &pPage);
|
rc = getPage(pBt, (Pgno)iTable, &pPage);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
rc = sqlite3BtreeClearTable(pBt, iTable);
|
rc = sqlite3BtreeClearTable(pBt, iTable);
|
||||||
if( rc ) return rc;
|
if( rc ){
|
||||||
|
releasePage(pPage);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
*piMoved = 0;
|
*piMoved = 0;
|
||||||
|
|
||||||
@@ -5755,3 +5772,16 @@ int sqlite3BtreeSync(Btree *pBt, const char *zMaster){
|
|||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
/*
|
||||||
|
** Reset the btree and underlying pager after a malloc() failure. Any
|
||||||
|
** transaction that was active when malloc() failed is rolled back.
|
||||||
|
*/
|
||||||
|
int sqlite3BtreeReset(Btree *pBt){
|
||||||
|
if( pBt->pCursor ) return SQLITE_BUSY;
|
||||||
|
pBt->inTrans = TRANS_NONE;
|
||||||
|
unlockBtreeIfUnused(pBt);
|
||||||
|
return sqlite3pager_reset(pBt->pPager);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** of what each interface routine does.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.62 2005/02/06 02:45:42 drh Exp $
|
** @(#) $Id: btree.h,v 1.63 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _BTREE_H_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@@ -73,6 +73,7 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
|||||||
int sqlite3BtreeIsInTrans(Btree*);
|
int sqlite3BtreeIsInTrans(Btree*);
|
||||||
int sqlite3BtreeIsInStmt(Btree*);
|
int sqlite3BtreeIsInStmt(Btree*);
|
||||||
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
int sqlite3BtreeSync(Btree*, const char *zMaster);
|
||||||
|
int sqlite3BtreeReset(Btree *);
|
||||||
|
|
||||||
const char *sqlite3BtreeGetFilename(Btree *);
|
const char *sqlite3BtreeGetFilename(Btree *);
|
||||||
const char *sqlite3BtreeGetDirname(Btree *);
|
const char *sqlite3BtreeGetDirname(Btree *);
|
||||||
|
73
src/main.c
73
src/main.c
@@ -14,7 +14,7 @@
|
|||||||
** other files are for internal use by SQLite and should not be
|
** other files are for internal use by SQLite and should not be
|
||||||
** accessed by users of the library.
|
** accessed by users of the library.
|
||||||
**
|
**
|
||||||
** $Id: main.c,v 1.282 2005/03/09 12:26:51 danielk1977 Exp $
|
** $Id: main.c,v 1.283 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -26,6 +26,16 @@
|
|||||||
*/
|
*/
|
||||||
const int sqlite3one = 1;
|
const int sqlite3one = 1;
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
/*
|
||||||
|
** Linked list of all open database handles. This is used by the
|
||||||
|
** sqlite3_global_recover() function. Entries are added to the list
|
||||||
|
** by openDatabase() and removed by sqlite3_close().
|
||||||
|
*/
|
||||||
|
static sqlite3 *pDbList = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Fill the InitData structure with an error message that indicates
|
** Fill the InitData structure with an error message that indicates
|
||||||
** that the database is corrupt.
|
** that the database is corrupt.
|
||||||
@@ -514,6 +524,23 @@ int sqlite3_close(sqlite3 *db){
|
|||||||
sqlite3ValueFree(db->pErr);
|
sqlite3ValueFree(db->pErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
{
|
||||||
|
sqlite3 *pPrev = pDbList;
|
||||||
|
sqlite3OsEnterMutex();
|
||||||
|
while( pPrev && pPrev->pNext!=db ){
|
||||||
|
pPrev = pPrev->pNext;
|
||||||
|
}
|
||||||
|
if( pPrev ){
|
||||||
|
pPrev->pNext = db->pNext;
|
||||||
|
}else{
|
||||||
|
assert( pDbList==db );
|
||||||
|
pDbList = db->pNext;
|
||||||
|
}
|
||||||
|
sqlite3OsLeaveMutex();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
db->magic = SQLITE_MAGIC_ERROR;
|
db->magic = SQLITE_MAGIC_ERROR;
|
||||||
sqliteFree(db);
|
sqliteFree(db);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
@@ -1199,6 +1226,14 @@ opendb_out:
|
|||||||
sqlite3Error(db, SQLITE_NOMEM, 0);
|
sqlite3Error(db, SQLITE_NOMEM, 0);
|
||||||
}
|
}
|
||||||
*ppDb = db;
|
*ppDb = db;
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
if( db ){
|
||||||
|
sqlite3OsEnterMutex();
|
||||||
|
db->pNext = pDbList;
|
||||||
|
pDbList = db;
|
||||||
|
sqlite3OsLeaveMutex();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return sqlite3_errcode(db);
|
return sqlite3_errcode(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1400,3 +1435,39 @@ int sqlite3_collation_needed16(
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_UTF16 */
|
#endif /* SQLITE_OMIT_UTF16 */
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
/*
|
||||||
|
** This function is called to recover from a malloc failure that occured
|
||||||
|
** within SQLite.
|
||||||
|
**
|
||||||
|
** This function is *not* threadsafe. Calling this from within a threaded
|
||||||
|
** application when threads other than the caller have used SQLite is
|
||||||
|
** dangerous and will almost certainly result in malfunctions.
|
||||||
|
*/
|
||||||
|
int sqlite3_global_recover(){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
|
if( sqlite3_malloc_failed ){
|
||||||
|
sqlite3 *db;
|
||||||
|
int i;
|
||||||
|
sqlite3_malloc_failed = 0;
|
||||||
|
for(db=pDbList; db; db=db->pNext ){
|
||||||
|
sqlite3ExpirePreparedStatements(db);
|
||||||
|
for(i=0; i<db->nDb; i++){
|
||||||
|
Btree *pBt = db->aDb[i].pBt;
|
||||||
|
if( pBt && (rc=sqlite3BtreeReset(pBt)) ){
|
||||||
|
goto recover_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db->autoCommit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recover_out:
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
sqlite3_malloc_failed = 1;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
24
src/pager.c
24
src/pager.c
@@ -18,7 +18,7 @@
|
|||||||
** file simultaneously, or one process from reading the database while
|
** file simultaneously, or one process from reading the database while
|
||||||
** another is writing.
|
** another is writing.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.c,v 1.197 2005/03/21 03:53:38 danielk1977 Exp $
|
** @(#) $Id: pager.c,v 1.198 2005/03/21 04:04:02 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -844,6 +844,28 @@ static void pager_reset(Pager *pPager){
|
|||||||
assert( pPager->journalOpen==0 );
|
assert( pPager->journalOpen==0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is used to reset the pager after a malloc() failure. This
|
||||||
|
** doesn't work with in-memory databases. If a malloc() fails when an
|
||||||
|
** in-memory database is in use it is not possible to recover.
|
||||||
|
**
|
||||||
|
** If a transaction or statement transaction is active, it is rolled back.
|
||||||
|
**
|
||||||
|
** It is an error to call this function if any pages are in use.
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
int sqlite3pager_reset(Pager *pPager){
|
||||||
|
if( pPager ){
|
||||||
|
if( pPager->nRef || MEMDB ){
|
||||||
|
return SQLITE_ERROR;
|
||||||
|
}
|
||||||
|
pPager->errMask &= ~(PAGER_ERR_MEM);
|
||||||
|
pager_reset(pPager);
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** When this routine is called, the pager has the journal file open and
|
** When this routine is called, the pager has the journal file open and
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
** subsystem. The page cache subsystem reads and writes a file a page
|
** subsystem. The page cache subsystem reads and writes a file a page
|
||||||
** at a time and provides a journal for rollback.
|
** at a time and provides a journal for rollback.
|
||||||
**
|
**
|
||||||
** @(#) $Id: pager.h,v 1.41 2005/02/06 02:45:42 drh Exp $
|
** @(#) $Id: pager.h,v 1.42 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -100,6 +100,7 @@ const char *sqlite3pager_journalname(Pager*);
|
|||||||
int sqlite3pager_rename(Pager*, const char *zNewName);
|
int sqlite3pager_rename(Pager*, const char *zNewName);
|
||||||
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
|
||||||
int sqlite3pager_movepage(Pager*,void*,Pgno);
|
int sqlite3pager_movepage(Pager*,void*,Pgno);
|
||||||
|
int sqlite3pager_reset(Pager*);
|
||||||
|
|
||||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
|
||||||
int sqlite3pager_lockstate(Pager*);
|
int sqlite3pager_lockstate(Pager*);
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
** This header file defines the interface that the SQLite library
|
** This header file defines the interface that the SQLite library
|
||||||
** presents to client programs.
|
** presents to client programs.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqlite.h.in,v 1.130 2005/02/05 07:33:35 danielk1977 Exp $
|
** @(#) $Id: sqlite.h.in,v 1.131 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITE3_H_
|
#ifndef _SQLITE3_H_
|
||||||
#define _SQLITE3_H_
|
#define _SQLITE3_H_
|
||||||
@@ -1215,11 +1215,32 @@ int sqlite3_expired(sqlite3_stmt*);
|
|||||||
** is NULL pointer, then SQLite does a search for an appropriate temporary
|
** is NULL pointer, then SQLite does a search for an appropriate temporary
|
||||||
** file directory.
|
** file directory.
|
||||||
**
|
**
|
||||||
** Once sqlite3_open() has been called, changing this variable will invalidate the
|
** Once sqlite3_open() has been called, changing this variable will invalidate
|
||||||
** current temporary database, if any.
|
** the current temporary database, if any.
|
||||||
*/
|
*/
|
||||||
extern char *sqlite3_temp_directory;
|
extern char *sqlite3_temp_directory;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This function is called to recover from a malloc() failure that occured
|
||||||
|
** within the SQLite library. Normally, after a single malloc() fails the
|
||||||
|
** library refuses to function (all major calls return SQLITE_NOMEM).
|
||||||
|
** This function library state so that it can be used again.
|
||||||
|
**
|
||||||
|
** All existing statements (sqlite3_stmt pointers) must be finalized or
|
||||||
|
** reset before this call is made. Otherwise, SQLITE_BUSY is returned.
|
||||||
|
** If any in-memory databases are in use, either as a main or TEMP
|
||||||
|
** database, SQLITE_ERROR is returned. In either of these cases, the
|
||||||
|
** library is not reset and remains unusable.
|
||||||
|
**
|
||||||
|
** This function is *not* threadsafe. Calling this from within a threaded
|
||||||
|
** application when threads other than the caller have used SQLite is
|
||||||
|
** dangerous and will almost certainly result in malfunctions.
|
||||||
|
**
|
||||||
|
** This functionality can be omitted from a build by defining the
|
||||||
|
** SQLITE_OMIT_GLOBALRECOVER at compile time.
|
||||||
|
*/
|
||||||
|
int sqlite3_global_recover();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* End of the 'extern "C"' block */
|
} /* End of the 'extern "C"' block */
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.373 2005/03/17 05:03:40 danielk1977 Exp $
|
** @(#) $Id: sqliteInt.h,v 1.374 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -452,6 +452,9 @@ struct sqlite3 {
|
|||||||
sqlite3_value *pErr; /* Most recent error message */
|
sqlite3_value *pErr; /* Most recent error message */
|
||||||
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
|
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
|
||||||
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
|
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
sqlite3 *pNext; /* Linked list of open db handles. */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
27
src/test1.c
27
src/test1.c
@@ -13,7 +13,7 @@
|
|||||||
** is not included in the SQLite library. It is used for automated
|
** is not included in the SQLite library. It is used for automated
|
||||||
** testing of the SQLite library.
|
** testing of the SQLite library.
|
||||||
**
|
**
|
||||||
** $Id: test1.c,v 1.134 2005/03/11 04:41:40 drh Exp $
|
** $Id: test1.c,v 1.135 2005/03/21 04:04:02 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "tcl.h"
|
#include "tcl.h"
|
||||||
@@ -2294,6 +2294,24 @@ static int test_stmt_utf8(
|
|||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int test_global_recover(
|
||||||
|
void * clientData,
|
||||||
|
Tcl_Interp *interp,
|
||||||
|
int objc,
|
||||||
|
Tcl_Obj *CONST objv[]
|
||||||
|
){
|
||||||
|
#ifndef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
int rc;
|
||||||
|
if( objc!=1 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 1, objv, "");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
rc = sqlite3_global_recover();
|
||||||
|
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
|
||||||
|
#endif
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite3_column_text STMT column
|
** Usage: sqlite3_column_text STMT column
|
||||||
**
|
**
|
||||||
@@ -2765,6 +2783,12 @@ static void set_options(Tcl_Interp *interp){
|
|||||||
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
|
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_OMIT_GLOBALRECOVER
|
||||||
|
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
|
||||||
|
#else
|
||||||
|
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "1", TCL_GLOBAL_ONLY);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_OMIT_INTEGRITY_CHECK
|
#ifdef SQLITE_OMIT_INTEGRITY_CHECK
|
||||||
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
|
Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY);
|
||||||
#else
|
#else
|
||||||
@@ -2952,6 +2976,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
|||||||
{ "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16},
|
{ "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16},
|
||||||
{ "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 },
|
{ "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 },
|
||||||
#endif
|
#endif
|
||||||
|
{ "sqlite3_global_recover", test_global_recover, 0 },
|
||||||
|
|
||||||
/* Functions from os.h */
|
/* Functions from os.h */
|
||||||
{ "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
|
{ "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
|
||||||
|
335
test/malloc2.test
Normal file
335
test/malloc2.test
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
# 2005 March 18
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file attempts to check that the library can recover from a malloc()
|
||||||
|
# failure when sqlite3_global_recover() is invoked.
|
||||||
|
#
|
||||||
|
# $Id: malloc2.test,v 1.1 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# Only run these tests if memory debugging is turned on.
|
||||||
|
#
|
||||||
|
if {[info command sqlite_malloc_stat]==""} {
|
||||||
|
puts "Skipping malloc tests: not compiled with -DSQLITE_DEBUG..."
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifcapable !globalrecover {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a checksum based on the contents of the database. If the
|
||||||
|
# checksum of two databases is the same, and the integrity-check passes
|
||||||
|
# for both, the two databases are identical.
|
||||||
|
#
|
||||||
|
proc cksum {db} {
|
||||||
|
set ret [list]
|
||||||
|
set sql {
|
||||||
|
SELECT name FROM sqlite_master WHERE type = 'table' UNION
|
||||||
|
SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION
|
||||||
|
SELECT 'sqlite_master' UNION
|
||||||
|
SELECT 'sqlite_temp_master'
|
||||||
|
}
|
||||||
|
foreach tbl [$db eval $sql] {
|
||||||
|
set cols [list]
|
||||||
|
$db eval "PRAGMA table_info($tbl)" {
|
||||||
|
lappend cols $name
|
||||||
|
}
|
||||||
|
set sql "SELECT md5sum([join $cols ,]) FROM $tbl"
|
||||||
|
lappend ret [db onecolumn $sql]
|
||||||
|
}
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
proc do_malloc2_test {tn args} {
|
||||||
|
array set ::mallocopts $args
|
||||||
|
set sum [cksum db]
|
||||||
|
|
||||||
|
for {set ::n 1} {true} {incr ::n} {
|
||||||
|
|
||||||
|
# Run the SQL. Malloc number $::n is set to fail. A malloc() failure
|
||||||
|
# may or may not be reported.
|
||||||
|
sqlite_malloc_fail $::n
|
||||||
|
do_test malloc2-$tn.$::n.2 {
|
||||||
|
set res [catchsql $::mallocopts(-sql)]
|
||||||
|
set rc [expr {
|
||||||
|
0==[string compare $res {1 {out of memory}}] ||
|
||||||
|
0==[lindex $res 0]
|
||||||
|
}]
|
||||||
|
if {$rc!=1} {
|
||||||
|
puts "Error: $res"
|
||||||
|
}
|
||||||
|
set rc
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
# If $::n is greater than the number of malloc() calls required to
|
||||||
|
# execute the SQL, then this test is finished. Break out of the loop.
|
||||||
|
if {[lindex [sqlite_malloc_stat] 2]>0} {
|
||||||
|
sqlite_malloc_fail -1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
# Nothing should work now, because the allocator should refuse to
|
||||||
|
# allocate any memory.
|
||||||
|
do_test malloc2-$tn.$::n.3 {
|
||||||
|
catchsql {SELECT 'nothing should work'}
|
||||||
|
} {1 {out of memory}}
|
||||||
|
|
||||||
|
# Recover from the malloc failure.
|
||||||
|
do_test malloc2-$tn.$::n.4 {
|
||||||
|
if 0 {
|
||||||
|
db close
|
||||||
|
sqlite_malloc_fail -1
|
||||||
|
set ::DB [sqlite3 db test.db]
|
||||||
|
set dummy SQLITE_OK
|
||||||
|
} else {
|
||||||
|
sqlite3_global_recover
|
||||||
|
}
|
||||||
|
} {SQLITE_OK}
|
||||||
|
|
||||||
|
# Checksum the database.
|
||||||
|
do_test malloc2-$tn.$::n.5 {
|
||||||
|
cksum db
|
||||||
|
} $sum
|
||||||
|
|
||||||
|
integrity_check malloc2-$tn.$::n.6
|
||||||
|
if {$::nErr>1} return
|
||||||
|
}
|
||||||
|
unset ::mallocopts
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test malloc2.1.setup {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE abc(a, b, c);
|
||||||
|
INSERT INTO abc VALUES(10, 20, 30);
|
||||||
|
INSERT INTO abc VALUES(40, 50, 60);
|
||||||
|
CREATE INDEX abc_i ON abc(a, b, c);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_malloc2_test 1.1 -sql {
|
||||||
|
SELECT * FROM abc;
|
||||||
|
}
|
||||||
|
do_malloc2_test 1.2 -sql {
|
||||||
|
UPDATE abc SET c = c+10;
|
||||||
|
}
|
||||||
|
do_malloc2_test 1.3 -sql {
|
||||||
|
INSERT INTO abc VALUES(70, 80, 90);
|
||||||
|
}
|
||||||
|
do_malloc2_test 1.4 -sql {
|
||||||
|
DELETE FROM abc;
|
||||||
|
}
|
||||||
|
do_test malloc2.1.5 {
|
||||||
|
execsql {
|
||||||
|
SELECT * FROM abc;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test malloc2.2.setup {
|
||||||
|
execsql {
|
||||||
|
CREATE TABLE def(a, b, c);
|
||||||
|
CREATE INDEX def_i1 ON def(a);
|
||||||
|
CREATE INDEX def_i2 ON def(c);
|
||||||
|
BEGIN;
|
||||||
|
}
|
||||||
|
for {set i 0} {$i<20} {incr i} {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO def VALUES(randstr(300,300),randstr(300,300),randstr(300,300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_malloc2_test 2 -sql {
|
||||||
|
BEGIN;
|
||||||
|
UPDATE def SET a = randstr(100,100) WHERE (oid%9)==0;
|
||||||
|
INSERT INTO def SELECT * FROM def WHERE (oid%13)==0;
|
||||||
|
|
||||||
|
CREATE INDEX def_i3 ON def(b);
|
||||||
|
|
||||||
|
UPDATE def SET a = randstr(100,100) WHERE (oid%9)==1;
|
||||||
|
INSERT INTO def SELECT * FROM def WHERE (oid%13)==1;
|
||||||
|
|
||||||
|
CREATE TABLE def2 AS SELECT * FROM def;
|
||||||
|
DROP TABLE def;
|
||||||
|
CREATE TABLE def AS SELECT * FROM def2;
|
||||||
|
DROP TABLE def2;
|
||||||
|
|
||||||
|
DELETE FROM def WHERE (oid%9)==2;
|
||||||
|
INSERT INTO def SELECT * FROM def WHERE (oid%13)==2;
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_test malloc2.3.setup {
|
||||||
|
execsql {
|
||||||
|
CREATE TEMP TABLE ghi(a, b, c);
|
||||||
|
BEGIN;
|
||||||
|
}
|
||||||
|
for {set i 0} {$i<20} {incr i} {
|
||||||
|
execsql {
|
||||||
|
INSERT INTO ghi VALUES(randstr(300,300),randstr(300,300),randstr(300,300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
execsql {
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_malloc2_test 3 -sql {
|
||||||
|
BEGIN;
|
||||||
|
CREATE INDEX ghi_i1 ON ghi(a);
|
||||||
|
UPDATE def SET a = randstr(100,100) WHERE (oid%2)==0;
|
||||||
|
UPDATE ghi SET a = randstr(100,100) WHERE (oid%2)==0;
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# The test cases below are to increase the code coverage in btree.c and
|
||||||
|
# pager.c of this test file. The idea is that each malloc() that occurs in
|
||||||
|
# these two source files should be made to fail at least once.
|
||||||
|
#
|
||||||
|
catchsql {
|
||||||
|
DROP TABLE ghi;
|
||||||
|
}
|
||||||
|
do_malloc2_test 4.1 -sql {
|
||||||
|
SELECT * FROM def ORDER BY oid ASC;
|
||||||
|
SELECT * FROM def ORDER BY oid DESC;
|
||||||
|
}
|
||||||
|
do_malloc2_test 4.2 -sql {
|
||||||
|
PRAGMA cache_size = 10;
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
-- This will put about 25 pages on the free list.
|
||||||
|
DELETE FROM def WHERE 1;
|
||||||
|
|
||||||
|
-- Allocate 32 new root pages. This will exercise the 'extract specific
|
||||||
|
-- page from the freelist' code when in auto-vacuum mode (see the
|
||||||
|
-- allocatePage() routine in btree.c).
|
||||||
|
CREATE TABLE t1(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t2(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t3(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t4(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t5(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t6(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t7(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
CREATE TABLE t8(a UNIQUE, b UNIQUE, c UNIQUE);
|
||||||
|
|
||||||
|
ROLLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Test that the global linked list of database handles works. An assert()
|
||||||
|
# will fail if there is some problem.
|
||||||
|
do_test malloc2-5 {
|
||||||
|
sqlite3 db1 test.db
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
sqlite3 db3 test.db
|
||||||
|
sqlite3 db4 test.db
|
||||||
|
sqlite3 db5 test.db
|
||||||
|
|
||||||
|
# Close the head of the list:
|
||||||
|
db5 close
|
||||||
|
|
||||||
|
# Close the end of the list:
|
||||||
|
db1 close
|
||||||
|
|
||||||
|
# Close a handle from the middle of the list:
|
||||||
|
db3 close
|
||||||
|
|
||||||
|
# Close the other two. Then open and close one more database, to make
|
||||||
|
# sure the head of the list was set back to NULL.
|
||||||
|
db2 close
|
||||||
|
db4 close
|
||||||
|
sqlite db1 test.db
|
||||||
|
db1 close
|
||||||
|
} {}
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check that if a statement is active sqlite3_global_recover doesn't reset
|
||||||
|
# the sqlite3_malloc_failed variable.
|
||||||
|
do_test malloc2-6.1 {
|
||||||
|
set ::STMT [sqlite3_prepare $::DB {SELECT * FROM def} -1 DUMMY]
|
||||||
|
sqlite3_step $::STMT
|
||||||
|
} {SQLITE_ROW}
|
||||||
|
do_test malloc2-6.2 {
|
||||||
|
sqlite3 db1 test.db
|
||||||
|
sqlite_malloc_fail 100
|
||||||
|
catchsql {
|
||||||
|
SELECT * FROM def;
|
||||||
|
} db1
|
||||||
|
} {1 {out of memory}}
|
||||||
|
do_test malloc2-6.3 {
|
||||||
|
sqlite3_global_recover
|
||||||
|
} {SQLITE_BUSY}
|
||||||
|
do_test malloc2-6.4 {
|
||||||
|
catchsql {
|
||||||
|
SELECT 'hello';
|
||||||
|
}
|
||||||
|
} {1 {out of memory}}
|
||||||
|
do_test malloc2-6.5 {
|
||||||
|
sqlite3_reset $::STMT
|
||||||
|
} {SQLITE_OK}
|
||||||
|
do_test malloc2-6.6 {
|
||||||
|
sqlite3_global_recover
|
||||||
|
} {SQLITE_OK}
|
||||||
|
do_test malloc2-6.7 {
|
||||||
|
catchsql {
|
||||||
|
SELECT 'hello';
|
||||||
|
}
|
||||||
|
} {0 hello}
|
||||||
|
do_test malloc2-6.8 {
|
||||||
|
sqlite3_step $::STMT
|
||||||
|
} {SQLITE_ERROR}
|
||||||
|
do_test malloc2-6.9 {
|
||||||
|
sqlite3_finalize $::STMT
|
||||||
|
} {SQLITE_SCHEMA}
|
||||||
|
do_test malloc2-6.10 {
|
||||||
|
db1 close
|
||||||
|
} {}
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Check that if an in-memory database is being used it is not possible
|
||||||
|
# to recover from a malloc() failure.
|
||||||
|
ifcapable memorydb {
|
||||||
|
do_test malloc2-7.1 {
|
||||||
|
sqlite3 db1 :memory:
|
||||||
|
list
|
||||||
|
} {}
|
||||||
|
do_test malloc2-7.2 {
|
||||||
|
sqlite_malloc_fail 100
|
||||||
|
catchsql {
|
||||||
|
SELECT * FROM def;
|
||||||
|
}
|
||||||
|
} {1 {out of memory}}
|
||||||
|
do_test malloc2-7.3 {
|
||||||
|
sqlite3_global_recover
|
||||||
|
} {SQLITE_ERROR}
|
||||||
|
do_test malloc2-7.4 {
|
||||||
|
catchsql {
|
||||||
|
SELECT 'hello';
|
||||||
|
}
|
||||||
|
} {1 {out of memory}}
|
||||||
|
do_test malloc2-7.5 {
|
||||||
|
db1 close
|
||||||
|
} {}
|
||||||
|
do_test malloc2-7.6 {
|
||||||
|
sqlite3_global_recover
|
||||||
|
} {SQLITE_OK}
|
||||||
|
do_test malloc2-7.7 {
|
||||||
|
catchsql {
|
||||||
|
SELECT 'hello';
|
||||||
|
}
|
||||||
|
} {0 hello}
|
||||||
|
}
|
||||||
|
|
||||||
|
finish_test
|
@@ -10,7 +10,7 @@
|
|||||||
#***********************************************************************
|
#***********************************************************************
|
||||||
# This file runs all tests.
|
# This file runs all tests.
|
||||||
#
|
#
|
||||||
# $Id: quick.test,v 1.33 2004/11/13 13:19:56 danielk1977 Exp $
|
# $Id: quick.test,v 1.34 2005/03/21 04:04:03 danielk1977 Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@@ -28,6 +28,7 @@ set EXCLUDE {
|
|||||||
corrupt.test
|
corrupt.test
|
||||||
crash.test
|
crash.test
|
||||||
malloc.test
|
malloc.test
|
||||||
|
malloc2.test
|
||||||
memleak.test
|
memleak.test
|
||||||
misuse.test
|
misuse.test
|
||||||
quick.test
|
quick.test
|
||||||
|
Reference in New Issue
Block a user