mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Merge in all the latest changes from trunk.
FossilOrigin-Name: b11d941e92897663da46160185e6e305d4e28fe6
This commit is contained in:
0
install-sh
Normal file → Executable file
0
install-sh
Normal file → Executable file
1
main.mk
1
main.mk
@@ -254,6 +254,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_server.c \
|
||||
$(TOP)/src/test_stat.c \
|
||||
$(TOP)/src/test_superlock.c \
|
||||
$(TOP)/src/test_syscall.c \
|
||||
$(TOP)/src/test_tclvar.c \
|
||||
$(TOP)/src/test_thread.c \
|
||||
$(TOP)/src/test_vfs.c \
|
||||
|
52
manifest
52
manifest
@@ -1,5 +1,5 @@
|
||||
C Improve\scoverage\sof\ssession\smodule\sa\sbit\smore.
|
||||
D 2011-03-25T19:06:10
|
||||
C Merge\sin\sall\sthe\slatest\schanges\sfrom\strunk.
|
||||
D 2011-03-30T02:03:12.567
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -108,9 +108,9 @@ F ext/session/sessionfault.test 2544a2e2ecad56e3c07a32c09799871d243c114c
|
||||
F ext/session/sqlite3session.c 9be8ccee4248681700659b89a81ae5c6cb8afacc
|
||||
F ext/session/sqlite3session.h f284bac51c12de0e0096fc986e61f5ae6b9e5be5
|
||||
F ext/session/test_session.c f8fdf5c110898b2bbc20c475fca879664c77fb5a
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
|
||||
F main.mk e283752f215b7055cdc48399da82033b67024e42
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
|
||||
@@ -127,13 +127,13 @@ F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
|
||||
F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07
|
||||
F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e
|
||||
F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c 43302cc4f3de6479b90fa6bb271b65d86333d00e
|
||||
F src/btree.h e2f2cd9933bf30724f53ffa12c4c5a3a864bbd6e
|
||||
F src/btree.c 2b9c81ff64da339a67dda4f94c0d763627be0b67
|
||||
F src/btree.h 8d36f774ec4b1d0027b8966f8c03d9a72a518c14
|
||||
F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
|
||||
F src/build.c 821d4b3c6b1da068a4eb1e9c8c414b75612d34c2
|
||||
F src/build.c 6c490fe14dedb094a202f559e3b29a276abffcf8
|
||||
F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01
|
||||
@@ -171,7 +171,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf
|
||||
F src/os_unix.c 942a9dca5d17c599300127c88a48413e6d55666f
|
||||
F src/os_unix.c 0b37759312e8adb58c0c7dab1ab8ca16957bf299
|
||||
F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
|
||||
F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
|
||||
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
|
||||
@@ -187,13 +187,13 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c d24406c45dd2442eb2eeaac413439066b149c944
|
||||
F src/shell.c 9dc0b4bb59290c0a35256d278cab0f314987ad6a
|
||||
F src/sqlite.h.in 846a91e163497b596b5bbebd26477eaf234eb1c0
|
||||
F src/sqlite.h.in 73512de44f0d3563dd24be2e701542e52c7efe25
|
||||
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
|
||||
F src/sqliteInt.h 7c11f9a648cf82e87330fd2185fcaa1f7c46dfba
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 78713534e628ea92b032bfa20ea8a1afc6cdb124
|
||||
F src/tclsqlite.c c233c25153b6fa3b511bc65df352cb8f97a0f81d
|
||||
F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
|
||||
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
|
||||
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
|
||||
@@ -229,26 +229,27 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
|
||||
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c d12e8cd163cd33b66d0a3d1b8daaf136d09d65c2
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
|
||||
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86
|
||||
F src/test_vfstrace.c f5c3b3b893d81a580d0f577e6d9bcfc1fd496136
|
||||
F src/test_vfstrace.c 2265c9895f350c8d3c39b079998fbe7481505cc1
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
|
||||
F src/trigger.c ec4813709e990a169b6923293e839fa5dfd64282
|
||||
F src/update.c f81e9b326cafba3fbe493141e396f3bbfba1d99b
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
|
||||
F src/util.c cd997077bad039efc0597eb027c929658f93c018
|
||||
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
|
||||
F src/vdbe.c c90edafd941481506f001b17cd8523683fdac853
|
||||
F src/vdbe.c 175a42d0f12b92093a7335402dbb46bfe7e360b0
|
||||
F src/vdbe.h edef9c4f0be83e1f1dccd049da37b40e021b63d9
|
||||
F src/vdbeInt.h b6748a8ac9be169d83585a0f5daf747863c6b8db
|
||||
F src/vdbeapi.c e472b3e5985175e948e70025cb3bffa8a2e185c8
|
||||
F src/vdbeaux.c af3be34b1980e428972ea11ef3a1d88acf8f2b9d
|
||||
F src/vdbeaux.c 051a1609e578418d1bfc6d2420b8eb412a7aea97
|
||||
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
|
||||
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
|
||||
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
|
||||
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
|
||||
F src/vtab.c e1edca38c4c4310710635bb91bb3c87fdf60f21d
|
||||
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
|
||||
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
@@ -290,6 +291,7 @@ F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49
|
||||
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
F test/badutf2.test a47fda0d986d5325aa0ec2a0ebdd2d68db45e623
|
||||
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
|
||||
F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
@@ -466,7 +468,7 @@ F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
|
||||
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
|
||||
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
|
||||
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
|
||||
F test/fts3fault2.test f275554f4a4fc7abf71e2975a9d6f4693f390526
|
||||
F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
|
||||
F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
|
||||
F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
|
||||
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
|
||||
@@ -567,7 +569,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
|
||||
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
|
||||
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 660b82ab528521cc4a48ff6df05ca3b6a00d47c5
|
||||
F test/malloc_common.tcl 50d0ed21eed0ae9548b58935bd29ac89a05a54fa
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
@@ -611,7 +613,7 @@ F test/permutations.test 1e35edce72e6d9e2e392420caed18652a97b1a95
|
||||
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
|
||||
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
|
||||
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x
|
||||
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
F test/quota.test ddafe133653093eb9a99ccd6264884ae43f9c9b8
|
||||
@@ -680,8 +682,10 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
|
||||
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
|
||||
F test/syscall.test 125d9781d914c408e8629053b5f914dc920ab3eb
|
||||
F test/sysfault.test be42aa42f89a82305cf3807047d419595e430480
|
||||
F test/table.test 04ba066432430657712d167ebf28080fe878d305
|
||||
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
|
||||
@@ -925,7 +929,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 666123c8d07be87d477e67b1cebef2b0fba5b4bc
|
||||
R 06396f39a2dba603f238d63a566a7e13
|
||||
U dan
|
||||
Z 44bcd7637527a5a2be65b60012fc28ed
|
||||
P 4255a9f609c4fd43582a0874143eabe211199726 3d2de011814002e2e25b7645f94ff8fc7aab9cdd
|
||||
R 48b479c7a408c0c8015c6f938b7e92a4
|
||||
U drh
|
||||
Z 1cd943e96dc4b8cfc7720b21a63156f8
|
||||
|
@@ -1 +1 @@
|
||||
4255a9f609c4fd43582a0874143eabe211199726
|
||||
b11d941e92897663da46160185e6e305d4e28fe6
|
@@ -488,7 +488,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
|
||||
/* Finish committing the transaction to the destination database. */
|
||||
if( SQLITE_OK==rc
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest))
|
||||
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
|
||||
){
|
||||
rc = SQLITE_DONE;
|
||||
}
|
||||
@@ -502,7 +502,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
|
||||
if( bCloseTrans ){
|
||||
TESTONLY( int rc2 );
|
||||
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc);
|
||||
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
|
||||
assert( rc2==SQLITE_OK );
|
||||
}
|
||||
|
||||
|
17
src/btree.c
17
src/btree.c
@@ -3160,10 +3160,21 @@ static void btreeEndTransaction(Btree *p){
|
||||
** the rollback journal (which causes the transaction to commit) and
|
||||
** drop locks.
|
||||
**
|
||||
** Normally, if an error occurs while the pager layer is attempting to
|
||||
** finalize the underlying journal file, this function returns an error and
|
||||
** the upper layer will attempt a rollback. However, if the second argument
|
||||
** is non-zero then this b-tree transaction is part of a multi-file
|
||||
** transaction. In this case, the transaction has already been committed
|
||||
** (by deleting a master journal file) and the caller will ignore this
|
||||
** functions return code. So, even if an error occurs in the pager layer,
|
||||
** reset the b-tree objects internal state to indicate that the write
|
||||
** transaction has been closed. This is quite safe, as the pager will have
|
||||
** transitioned to the error state.
|
||||
**
|
||||
** This will release the write lock on the database file. If there
|
||||
** are no active cursors, it also releases the read lock.
|
||||
*/
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree *p){
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree *p, int bCleanup){
|
||||
|
||||
if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
|
||||
sqlite3BtreeEnter(p);
|
||||
@@ -3178,7 +3189,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
assert( pBt->nTransaction>0 );
|
||||
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( rc!=SQLITE_OK && bCleanup==0 ){
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
}
|
||||
@@ -3198,7 +3209,7 @@ int sqlite3BtreeCommit(Btree *p){
|
||||
sqlite3BtreeEnter(p);
|
||||
rc = sqlite3BtreeCommitPhaseOne(p, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeCommitPhaseTwo(p);
|
||||
rc = sqlite3BtreeCommitPhaseTwo(p, 0);
|
||||
}
|
||||
sqlite3BtreeLeave(p);
|
||||
return rc;
|
||||
|
@@ -87,7 +87,7 @@ int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*);
|
||||
int sqlite3BtreeBeginStmt(Btree*,int);
|
||||
|
@@ -368,7 +368,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
|
||||
|
||||
len = sqlite3Strlen30(zIdxName);
|
||||
pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
|
||||
if( pIndex ){
|
||||
if( ALWAYS(pIndex) ){
|
||||
if( pIndex->pTable->pIndex==pIndex ){
|
||||
pIndex->pTable->pIndex = pIndex->pNext;
|
||||
}else{
|
||||
|
@@ -371,7 +371,7 @@ static struct unix_syscall {
|
||||
#else
|
||||
{ "fallocate", (sqlite3_syscall_ptr)0, 0 },
|
||||
#endif
|
||||
#define osFallocate ((int(*)(int,off_t,off_t)aSyscall[15].pCurrent)
|
||||
#define osFallocate ((int(*)(int,off_t,off_t))aSyscall[15].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
@@ -444,18 +444,16 @@ static sqlite3_syscall_ptr unixGetSystemCall(
|
||||
** system call.
|
||||
*/
|
||||
static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
|
||||
unsigned int i;
|
||||
int i = -1;
|
||||
|
||||
UNUSED_PARAMETER(p);
|
||||
if( zName==0 ){
|
||||
i = -1;
|
||||
}else{
|
||||
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0])-1; i++){
|
||||
if( strcmp(zName, aSyscall[0].zName)==0 ) break;
|
||||
if( zName ){
|
||||
for(i=0; i<ArraySize(aSyscall)-1; i++){
|
||||
if( strcmp(zName, aSyscall[i].zName)==0 ) break;
|
||||
}
|
||||
}
|
||||
for(i++; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
|
||||
if( aSyscall[0].pCurrent!=0 ) return aSyscall[0].zName;
|
||||
for(i++; i<ArraySize(aSyscall); i++){
|
||||
if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -3380,8 +3378,8 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
|
||||
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
|
||||
int rc;
|
||||
do{
|
||||
rc = osFallocate(pFile->.h, buf.st_size, nSize-buf.st_size;
|
||||
}while( rc<0 && errno=EINTR );
|
||||
rc = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
|
||||
}while( rc<0 && errno==EINTR );
|
||||
if( rc ) return SQLITE_IOERR_WRITE;
|
||||
#else
|
||||
/* If the OS does not have posix_fallocate(), fake it. First use
|
||||
|
@@ -2975,7 +2975,9 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
|
||||
** column number. ^The leftmost column is number 0.
|
||||
**
|
||||
** ^The returned string pointer is valid until either the [prepared statement]
|
||||
** is destroyed by [sqlite3_finalize()] or until the next call to
|
||||
** is destroyed by [sqlite3_finalize()] or until the statement is automatically
|
||||
** reprepared by the first call to [sqlite3_step()] for a particular run
|
||||
** or until the next call to
|
||||
** sqlite3_column_name() or sqlite3_column_name16() on the same column.
|
||||
**
|
||||
** ^If sqlite3_malloc() fails during the processing of either routine
|
||||
@@ -3001,7 +3003,9 @@ const void *sqlite3_column_name16(sqlite3_stmt*, int N);
|
||||
** the database name, the _table_ routines return the table name, and
|
||||
** the origin_ routines return the column name.
|
||||
** ^The returned string is valid until the [prepared statement] is destroyed
|
||||
** using [sqlite3_finalize()] or until the same information is requested
|
||||
** using [sqlite3_finalize()] or until the statement is automatically
|
||||
** reprepared by the first call to [sqlite3_step()] for a particular run
|
||||
** or until the same information is requested
|
||||
** again in a different encoding.
|
||||
**
|
||||
** ^The names returned are the original un-aliased names of the
|
||||
|
@@ -3719,10 +3719,10 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int Sqlitequota_Init(Tcl_Interp*);
|
||||
extern int Sqlitemultiplex_Init(Tcl_Interp*);
|
||||
extern int SqliteSuperlock_Init(Tcl_Interp*);
|
||||
extern int SqlitetestSyscall_Init(Tcl_Interp*);
|
||||
#ifdef SQLITE_ENABLE_SESSION
|
||||
extern int TestSession_Init(Tcl_Interp*);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ZIPVFS
|
||||
extern int Zipvfs_Init(Tcl_Interp*);
|
||||
Zipvfs_Init(interp);
|
||||
@@ -3759,6 +3759,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
Sqlitequota_Init(interp);
|
||||
Sqlitemultiplex_Init(interp);
|
||||
SqliteSuperlock_Init(interp);
|
||||
SqlitetestSyscall_Init(interp);
|
||||
#ifdef SQLITE_ENABLE_SESSION
|
||||
TestSession_Init(interp);
|
||||
#endif
|
||||
|
642
src/test_syscall.c
Normal file
642
src/test_syscall.c
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
** 2011 March 28
|
||||
**
|
||||
** 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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** The code in this file implements a Tcl interface used to test error
|
||||
** handling in the os_unix.c module. Wrapper functions that support fault
|
||||
** injection are registered as the low-level OS functions using the
|
||||
** xSetSystemCall() method of the VFS. The Tcl interface is as follows:
|
||||
**
|
||||
**
|
||||
** test_syscall install LIST
|
||||
** Install wrapper functions for all system calls in argument LIST.
|
||||
** LIST must be a list consisting of zero or more of the following
|
||||
** literal values:
|
||||
**
|
||||
** open close access getcwd stat fstat
|
||||
** ftruncate fcntl read pread pread64 write
|
||||
** pwrite pwrite64 fchmod fallocate
|
||||
**
|
||||
** test_syscall uninstall
|
||||
** Uninstall all wrapper functions.
|
||||
**
|
||||
** test_syscall fault ?COUNT PERSIST?
|
||||
** If [test_syscall fault] is invoked without the two arguments, fault
|
||||
** injection is disabled. Otherwise, fault injection is configured to
|
||||
** cause a failure on the COUNT'th next call to a system call with a
|
||||
** wrapper function installed. A COUNT value of 1 means fail the next
|
||||
** system call.
|
||||
**
|
||||
** Argument PERSIST is interpreted as a boolean. If true, the all
|
||||
** system calls following the initial failure also fail. Otherwise, only
|
||||
** the single transient failure is injected.
|
||||
**
|
||||
** test_syscall errno CALL ERRNO
|
||||
** Set the value that the global "errno" is set to following a fault
|
||||
** in call CALL. Argument CALL must be one of the system call names
|
||||
** listed above (under [test_syscall install]). ERRNO is a symbolic
|
||||
** name (i.e. "EACCES"). Not all errno codes are supported. Add extra
|
||||
** to the aErrno table in function test_syscall_errno() below as
|
||||
** required.
|
||||
**
|
||||
** test_syscall reset ?SYSTEM-CALL?
|
||||
** With no argument, this is an alias for the [uninstall] command. However,
|
||||
** this command uses a VFS call of the form:
|
||||
**
|
||||
** xSetSystemCall(pVfs, 0, 0);
|
||||
**
|
||||
** To restore the default system calls. The [uninstall] command restores
|
||||
** each system call individually by calling (i.e.):
|
||||
**
|
||||
** xSetSystemCall(pVfs, "open", 0);
|
||||
**
|
||||
** With an argument, this command attempts to reset the system call named
|
||||
** by the parameter using the same method as [uninstall].
|
||||
**
|
||||
** test_syscall exists SYSTEM-CALL
|
||||
** Return true if the named system call exists. Or false otherwise.
|
||||
**
|
||||
** test_syscall list
|
||||
** Return a list of all system calls. The list is constructed using
|
||||
** the xNextSystemCall() VFS method.
|
||||
*/
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef SQLITE_OS_UNIX
|
||||
|
||||
/* From test1.c */
|
||||
extern const char *sqlite3TestErrorName(int);
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
static struct TestSyscallGlobal {
|
||||
int bPersist; /* 1 for persistent errors, 0 for transient */
|
||||
int nCount; /* Fail after this many more calls */
|
||||
int nFail; /* Number of failures that have occurred */
|
||||
} gSyscall = { 0, 0 };
|
||||
|
||||
static int ts_open(const char *, int, int);
|
||||
static int ts_close(int fd);
|
||||
static int ts_access(const char *zPath, int mode);
|
||||
static char *ts_getcwd(char *zPath, size_t nPath);
|
||||
static int ts_stat(const char *zPath, struct stat *p);
|
||||
static int ts_fstat(int fd, struct stat *p);
|
||||
static int ts_ftruncate(int fd, off_t n);
|
||||
static int ts_fcntl(int fd, int cmd, ... );
|
||||
static int ts_read(int fd, void *aBuf, size_t nBuf);
|
||||
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off);
|
||||
static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off);
|
||||
static int ts_write(int fd, const void *aBuf, size_t nBuf);
|
||||
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
|
||||
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
|
||||
static int ts_fchmod(int fd, mode_t mode);
|
||||
static int ts_fallocate(int fd, off_t off, off_t len);
|
||||
|
||||
|
||||
struct TestSyscallArray {
|
||||
const char *zName;
|
||||
sqlite3_syscall_ptr xTest;
|
||||
sqlite3_syscall_ptr xOrig;
|
||||
int default_errno; /* Default value for errno following errors */
|
||||
int custom_errno; /* Current value for errno if error */
|
||||
} aSyscall[] = {
|
||||
/* 0 */ { "open", (sqlite3_syscall_ptr)ts_open, 0, EACCES, 0 },
|
||||
/* 1 */ { "close", (sqlite3_syscall_ptr)ts_close, 0, 0, 0 },
|
||||
/* 2 */ { "access", (sqlite3_syscall_ptr)ts_access, 0, 0, 0 },
|
||||
/* 3 */ { "getcwd", (sqlite3_syscall_ptr)ts_getcwd, 0, 0, 0 },
|
||||
/* 4 */ { "stat", (sqlite3_syscall_ptr)ts_stat, 0, 0, 0 },
|
||||
/* 5 */ { "fstat", (sqlite3_syscall_ptr)ts_fstat, 0, 0, 0 },
|
||||
/* 6 */ { "ftruncate", (sqlite3_syscall_ptr)ts_ftruncate, 0, EIO, 0 },
|
||||
/* 7 */ { "fcntl", (sqlite3_syscall_ptr)ts_fcntl, 0, 0, 0 },
|
||||
/* 8 */ { "read", (sqlite3_syscall_ptr)ts_read, 0, 0, 0 },
|
||||
/* 9 */ { "pread", (sqlite3_syscall_ptr)ts_pread, 0, 0, 0 },
|
||||
/* 10 */ { "pread64", (sqlite3_syscall_ptr)ts_pread64, 0, 0, 0 },
|
||||
/* 11 */ { "write", (sqlite3_syscall_ptr)ts_write, 0, 0, 0 },
|
||||
/* 12 */ { "pwrite", (sqlite3_syscall_ptr)ts_pwrite, 0, 0, 0 },
|
||||
/* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 },
|
||||
/* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 },
|
||||
/* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
#define orig_open ((int(*)(const char *, int, int))aSyscall[0].xOrig)
|
||||
#define orig_close ((int(*)(int))aSyscall[1].xOrig)
|
||||
#define orig_access ((int(*)(const char*,int))aSyscall[2].xOrig)
|
||||
#define orig_getcwd ((char*(*)(char*,size_t))aSyscall[3].xOrig)
|
||||
#define orig_stat ((int(*)(const char*,struct stat*))aSyscall[4].xOrig)
|
||||
#define orig_fstat ((int(*)(int,struct stat*))aSyscall[5].xOrig)
|
||||
#define orig_ftruncate ((int(*)(int,off_t))aSyscall[6].xOrig)
|
||||
#define orig_fcntl ((int(*)(int,int,...))aSyscall[7].xOrig)
|
||||
#define orig_read ((ssize_t(*)(int,void*,size_t))aSyscall[8].xOrig)
|
||||
#define orig_pread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].xOrig)
|
||||
#define orig_pread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].xOrig)
|
||||
#define orig_write ((ssize_t(*)(int,const void*,size_t))aSyscall[11].xOrig)
|
||||
#define orig_pwrite ((ssize_t(*)(int,const void*,size_t,off_t))\
|
||||
aSyscall[12].xOrig)
|
||||
#define orig_pwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\
|
||||
aSyscall[13].xOrig)
|
||||
#define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
|
||||
#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
|
||||
|
||||
/*
|
||||
** This function is called exactly once from within each invocation of a
|
||||
** system call wrapper in this file. It returns 1 if the function should
|
||||
** fail, or 0 if it should succeed.
|
||||
*/
|
||||
static int tsIsFail(void){
|
||||
gSyscall.nCount--;
|
||||
if( gSyscall.nCount==0 || (gSyscall.nFail && gSyscall.bPersist) ){
|
||||
gSyscall.nFail++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current error-number value for function zFunc. zFunc must be
|
||||
** the name of a system call in the aSyscall[] table.
|
||||
**
|
||||
** Usually, the current error-number is the value that errno should be set
|
||||
** to if the named system call fails. The exception is "fallocate". See
|
||||
** comments above the implementation of ts_fallocate() for details.
|
||||
*/
|
||||
static int tsErrno(const char *zFunc){
|
||||
int i;
|
||||
int nFunc = strlen(zFunc);
|
||||
for(i=0; aSyscall[i].zName; i++){
|
||||
if( strlen(aSyscall[i].zName)!=nFunc ) continue;
|
||||
if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
|
||||
return aSyscall[i].custom_errno;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around tsIsFail(). If tsIsFail() returns non-zero, set the
|
||||
** value of errno before returning.
|
||||
*/
|
||||
static int tsIsFailErrno(const char *zFunc){
|
||||
if( tsIsFail() ){
|
||||
errno = tsErrno(zFunc);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around open().
|
||||
*/
|
||||
static int ts_open(const char *zFile, int flags, int mode){
|
||||
if( tsIsFailErrno("open") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_open(zFile, flags, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around close().
|
||||
*/
|
||||
static int ts_close(int fd){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around access().
|
||||
*/
|
||||
static int ts_access(const char *zPath, int mode){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_access(zPath, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around getcwd().
|
||||
*/
|
||||
static char *ts_getcwd(char *zPath, size_t nPath){
|
||||
if( tsIsFail() ){
|
||||
return NULL;
|
||||
}
|
||||
return orig_getcwd(zPath, nPath);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around stat().
|
||||
*/
|
||||
static int ts_stat(const char *zPath, struct stat *p){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_stat(zPath, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around fstat().
|
||||
*/
|
||||
static int ts_fstat(int fd, struct stat *p){
|
||||
if( tsIsFailErrno("fstat") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_fstat(fd, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around ftruncate().
|
||||
*/
|
||||
static int ts_ftruncate(int fd, off_t n){
|
||||
if( tsIsFailErrno("ftruncate") ){
|
||||
return -1;
|
||||
}
|
||||
return orig_ftruncate(fd, n);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around fcntl().
|
||||
*/
|
||||
static int ts_fcntl(int fd, int cmd, ... ){
|
||||
va_list ap;
|
||||
void *pArg;
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
va_start(ap, cmd);
|
||||
pArg = va_arg(ap, void *);
|
||||
return orig_fcntl(fd, cmd, pArg);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around read().
|
||||
*/
|
||||
static int ts_read(int fd, void *aBuf, size_t nBuf){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_read(fd, aBuf, nBuf);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around pread().
|
||||
*/
|
||||
static int ts_pread(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pread(fd, aBuf, nBuf, off);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around pread64().
|
||||
*/
|
||||
static int ts_pread64(int fd, void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pread64(fd, aBuf, nBuf, off);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around write().
|
||||
*/
|
||||
static int ts_write(int fd, const void *aBuf, size_t nBuf){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_write(fd, aBuf, nBuf);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around pwrite().
|
||||
*/
|
||||
static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pwrite(fd, aBuf, nBuf, off);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around pwrite64().
|
||||
*/
|
||||
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_pwrite64(fd, aBuf, nBuf, off);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around fchmod().
|
||||
*/
|
||||
static int ts_fchmod(int fd, mode_t mode){
|
||||
if( tsIsFail() ){
|
||||
return -1;
|
||||
}
|
||||
return orig_fchmod(fd, mode);
|
||||
}
|
||||
|
||||
/*
|
||||
** A wrapper around fallocate().
|
||||
**
|
||||
** SQLite assumes that the fallocate() function is compatible with
|
||||
** posix_fallocate(). According to the Linux man page (2009-09-30):
|
||||
**
|
||||
** posix_fallocate() returns zero on success, or an error number on
|
||||
** failure. Note that errno is not set.
|
||||
*/
|
||||
static int ts_fallocate(int fd, off_t off, off_t len){
|
||||
if( tsIsFail() ){
|
||||
return tsErrno("fallocate");
|
||||
}
|
||||
return orig_fallocate(fd, off, len);
|
||||
}
|
||||
|
||||
static int test_syscall_install(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs;
|
||||
int nElem;
|
||||
int i;
|
||||
Tcl_Obj **apElem;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL-LIST");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_ListObjGetElements(interp, objv[2], &nElem, &apElem) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pVfs = sqlite3_vfs_find(0);
|
||||
|
||||
for(i=0; i<nElem; i++){
|
||||
int iCall;
|
||||
int rc = Tcl_GetIndexFromObjStruct(interp,
|
||||
apElem[i], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
|
||||
);
|
||||
if( rc ) return rc;
|
||||
if( aSyscall[iCall].xOrig==0 ){
|
||||
aSyscall[iCall].xOrig = pVfs->xGetSystemCall(pVfs, aSyscall[iCall].zName);
|
||||
pVfs->xSetSystemCall(pVfs, aSyscall[iCall].zName, aSyscall[iCall].xTest);
|
||||
}
|
||||
aSyscall[iCall].custom_errno = aSyscall[iCall].default_errno;
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_uninstall(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs;
|
||||
int i;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pVfs = sqlite3_vfs_find(0);
|
||||
for(i=0; aSyscall[i].zName; i++){
|
||||
if( aSyscall[i].xOrig ){
|
||||
pVfs->xSetSystemCall(pVfs, aSyscall[i].zName, 0);
|
||||
aSyscall[i].xOrig = 0;
|
||||
}
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_reset(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pVfs = sqlite3_vfs_find(0);
|
||||
if( objc==2 ){
|
||||
rc = pVfs->xSetSystemCall(pVfs, 0, 0);
|
||||
for(i=0; aSyscall[i].zName; i++) aSyscall[i].xOrig = 0;
|
||||
}else{
|
||||
int nFunc;
|
||||
char *zFunc = Tcl_GetStringFromObj(objv[2], &nFunc);
|
||||
rc = pVfs->xSetSystemCall(pVfs, Tcl_GetString(objv[2]), 0);
|
||||
for(i=0; rc==SQLITE_OK && aSyscall[i].zName; i++){
|
||||
if( strlen(aSyscall[i].zName)!=nFunc ) continue;
|
||||
if( memcmp(aSyscall[i].zName, zFunc, nFunc) ) continue;
|
||||
aSyscall[i].xOrig = 0;
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3TestErrorName(rc), -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
Tcl_ResetResult(interp);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_exists(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
sqlite3_vfs *pVfs;
|
||||
sqlite3_syscall_ptr x;
|
||||
|
||||
if( objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pVfs = sqlite3_vfs_find(0);
|
||||
x = pVfs->xGetSystemCall(pVfs, Tcl_GetString(objv[2]));
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(x!=0));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_fault(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int nCount = 0;
|
||||
int bPersist = 0;
|
||||
|
||||
if( objc!=2 && objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "?COUNT PERSIST?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( objc==4 ){
|
||||
if( Tcl_GetIntFromObj(interp, objv[2], &nCount)
|
||||
|| Tcl_GetBooleanFromObj(interp, objv[3], &bPersist)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(gSyscall.nFail));
|
||||
gSyscall.nCount = nCount;
|
||||
gSyscall.bPersist = bPersist;
|
||||
gSyscall.nFail = 0;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_errno(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int iCall;
|
||||
int iErrno;
|
||||
int rc;
|
||||
|
||||
struct Errno {
|
||||
const char *z;
|
||||
int i;
|
||||
} aErrno[] = {
|
||||
{ "EACCES", EACCES },
|
||||
{ "EINTR", EINTR },
|
||||
{ "EIO", EIO },
|
||||
{ "EOVERFLOW", EOVERFLOW },
|
||||
{ "ENOMEM", ENOMEM },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "SYSCALL ERRNO");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
rc = Tcl_GetIndexFromObjStruct(interp,
|
||||
objv[2], aSyscall, sizeof(aSyscall[0]), "system-call", 0, &iCall
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
rc = Tcl_GetIndexFromObjStruct(interp,
|
||||
objv[3], aErrno, sizeof(aErrno[0]), "errno", 0, &iErrno
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
|
||||
aSyscall[iCall].custom_errno = aErrno[iErrno].i;
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall_list(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
const char *zSys;
|
||||
sqlite3_vfs *pVfs;
|
||||
Tcl_Obj *pList;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 2, objv, "");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
pVfs = sqlite3_vfs_find(0);
|
||||
pList = Tcl_NewObj();
|
||||
Tcl_IncrRefCount(pList);
|
||||
for(zSys = pVfs->xNextSystemCall(pVfs, 0);
|
||||
zSys!=0;
|
||||
zSys = pVfs->xNextSystemCall(pVfs, zSys)
|
||||
){
|
||||
Tcl_ListObjAppendElement(interp, pList, Tcl_NewStringObj(zSys, -1));
|
||||
}
|
||||
|
||||
Tcl_SetObjResult(interp, pList);
|
||||
Tcl_DecrRefCount(pList);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
static int test_syscall(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
struct SyscallCmd {
|
||||
const char *zName;
|
||||
Tcl_ObjCmdProc *xCmd;
|
||||
} aCmd[] = {
|
||||
{ "fault", test_syscall_fault },
|
||||
{ "install", test_syscall_install },
|
||||
{ "uninstall", test_syscall_uninstall },
|
||||
{ "reset", test_syscall_reset },
|
||||
{ "errno", test_syscall_errno },
|
||||
{ "exists", test_syscall_exists },
|
||||
{ "list", test_syscall_list },
|
||||
{ 0, 0 }
|
||||
};
|
||||
int iCmd;
|
||||
int rc;
|
||||
|
||||
if( objc<2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND ...");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = Tcl_GetIndexFromObjStruct(interp,
|
||||
objv[1], aCmd, sizeof(aCmd[0]), "sub-command", 0, &iCmd
|
||||
);
|
||||
if( rc!=TCL_OK ) return rc;
|
||||
return aCmd[iCmd].xCmd(clientData, interp, objc, objv);
|
||||
}
|
||||
|
||||
int SqlitetestSyscall_Init(Tcl_Interp *interp){
|
||||
struct SyscallCmd {
|
||||
const char *zName;
|
||||
Tcl_ObjCmdProc *xCmd;
|
||||
} aCmd[] = {
|
||||
{ "test_syscall", test_syscall},
|
||||
};
|
||||
int i;
|
||||
|
||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xCmd, 0, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
#else
|
||||
int SqlitetestSyscall_Init(Tcl_Interp *interp){
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
@@ -77,8 +77,8 @@ static int vfstraceSleep(sqlite3_vfs*, int microseconds);
|
||||
static int vfstraceCurrentTime(sqlite3_vfs*, double*);
|
||||
static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
|
||||
static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
static int vfstraceSetSystemCall(sqlite3_vfs*, const char *zName, void *pFunc);
|
||||
static void *vfstraceGetSystemCall(sqlite3_vfs*, const char *zName);
|
||||
static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
|
||||
static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
|
||||
static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
|
||||
|
||||
/*
|
||||
@@ -682,13 +682,16 @@ static int vfstraceGetLastError(sqlite3_vfs *pVfs, int iErr, char *zErr){
|
||||
static int vfstraceSetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
void *pFunc
|
||||
sqlite3_syscall_ptr pFunc
|
||||
){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xSetSystemCall(pRoot, zName, pFunc);
|
||||
}
|
||||
static void *vfstraceGetSystemCall(sqlite3_vfs *pVfs, const char *zName){
|
||||
static sqlite3_syscall_ptr vfstraceGetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName
|
||||
){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xGetSystemCall(pRoot, zName);
|
||||
|
@@ -167,7 +167,7 @@ int sqlite3Utf8Read(
|
||||
const unsigned char *zIn, /* First byte of UTF-8 character */
|
||||
const unsigned char **pzNext /* Write first byte past UTF-8 char here */
|
||||
){
|
||||
int c;
|
||||
unsigned int c;
|
||||
|
||||
/* Same as READ_UTF8() above but without the zTerm parameter.
|
||||
** For this routine, we assume the UTF8 string is always zero-terminated.
|
||||
@@ -410,15 +410,15 @@ int sqlite3Utf8CharLen(const char *zIn, int nByte){
|
||||
** This has the effect of making sure that the string is well-formed
|
||||
** UTF-8. Miscoded characters are removed.
|
||||
**
|
||||
** The translation is done in-place (since it is impossible for the
|
||||
** correct UTF-8 encoding to be longer than a malformed encoding).
|
||||
** The translation is done in-place and aborted if the output
|
||||
** overruns the input.
|
||||
*/
|
||||
int sqlite3Utf8To8(unsigned char *zIn){
|
||||
unsigned char *zOut = zIn;
|
||||
unsigned char *zStart = zIn;
|
||||
u32 c;
|
||||
|
||||
while( zIn[0] ){
|
||||
while( zIn[0] && zOut<=zIn ){
|
||||
c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
|
||||
if( c!=0xfffd ){
|
||||
WRITE_UTF8(zOut, c);
|
||||
|
19
src/vdbe.c
19
src/vdbe.c
@@ -4646,14 +4646,10 @@ case OP_CreateTable: { /* out2-prerelease */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: ParseSchema P1 P2 * P4 *
|
||||
/* Opcode: ParseSchema P1 * * P4 *
|
||||
**
|
||||
** Read and parse all entries from the SQLITE_MASTER table of database P1
|
||||
** that match the WHERE clause P4. P2 is the "force" flag. Always do
|
||||
** the parsing if P2 is true. If P2 is false, then this routine is a
|
||||
** no-op if the schema is not currently loaded. In other words, if P2
|
||||
** is false, the SQLITE_MASTER table is only parsed if the rest of the
|
||||
** schema is already loaded into the symbol table.
|
||||
** that match the WHERE clause P4.
|
||||
**
|
||||
** This opcode invokes the parser to create a new virtual machine,
|
||||
** then runs the new virtual machine. It is thus a re-entrant opcode.
|
||||
@@ -4667,14 +4663,7 @@ case OP_ParseSchema: {
|
||||
iDb = pOp->p1;
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
|
||||
/* If pOp->p2 is 0, then this opcode is being executed to read a
|
||||
** single row, for example the row corresponding to a new index
|
||||
** created by this VDBE, from the sqlite_master table. It only
|
||||
** does this if the corresponding in-memory schema is currently
|
||||
** loaded. Otherwise, the new index definition can be loaded along
|
||||
** with the rest of the schema when it is required.
|
||||
**
|
||||
** Although the mutex on the BtShared object that corresponds to
|
||||
/* Although the mutex on the BtShared object that corresponds to
|
||||
** database iDb (the database containing the sqlite_master table
|
||||
** read by this instruction) is currently held, it is necessary to
|
||||
** obtain the mutexes on all attached databases before checking if
|
||||
@@ -4690,7 +4679,7 @@ case OP_ParseSchema: {
|
||||
*/
|
||||
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
|
||||
sqlite3BtreeEnterAll(db);
|
||||
if( pOp->p2 || DbHasProperty(db, iDb, DB_SchemaLoaded) ){
|
||||
if( ALWAYS(DbHasProperty(db, iDb, DB_SchemaLoaded)) ){
|
||||
zMaster = SCHEMA_TABLE(iDb);
|
||||
initData.db = db;
|
||||
initData.iDb = pOp->p1;
|
||||
|
@@ -1704,7 +1704,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
rc = sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -1836,7 +1836,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *pBt = db->aDb[i].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeCommitPhaseTwo(pBt);
|
||||
sqlite3BtreeCommitPhaseTwo(pBt, 1);
|
||||
}
|
||||
}
|
||||
sqlite3EndBenignMalloc();
|
||||
|
@@ -372,7 +372,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
|
||||
|
||||
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
|
||||
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 1, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, zWhere, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
|
||||
pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
|
||||
}
|
||||
|
119
test/badutf2.test
Normal file
119
test/badutf2.test
Normal file
@@ -0,0 +1,119 @@
|
||||
# 2011 March 15
|
||||
#
|
||||
# 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 implements regression tests for SQLite library.
|
||||
#
|
||||
# This file checks to make sure SQLite is able to gracEFully
|
||||
# handle malformed UTF-8.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
proc utf8_to_ustr2 {s} {
|
||||
set r ""
|
||||
foreach i [split $s ""] {
|
||||
scan $i %c c
|
||||
append r [format \\u%04.4X $c]
|
||||
}
|
||||
set r
|
||||
}
|
||||
|
||||
proc utf8_to_hstr {in} {
|
||||
regsub -all -- {(..)} $in {%[format "%s" \1]} out
|
||||
subst $out
|
||||
}
|
||||
|
||||
proc utf8_to_xstr {in} {
|
||||
regsub -all -- {(..)} $in {\\\\x[format "%s" \1]} out
|
||||
subst $out
|
||||
}
|
||||
|
||||
proc utf8_to_ustr {in} {
|
||||
regsub -all -- {(..)} $in {\\\\u[format "%04.4X" 0x\1]} out
|
||||
subst $out
|
||||
}
|
||||
|
||||
do_test badutf2-1.0 {
|
||||
db close
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval "PRAGMA encoding = 'UTF-8'"
|
||||
} {}
|
||||
|
||||
do_test badutf2-4.0 {
|
||||
set S [sqlite3_prepare_v2 db "SELECT ?" -1 dummy]
|
||||
sqlite3_expired $S
|
||||
} {0}
|
||||
|
||||
foreach { i len uval xstr ustr u2u } {
|
||||
1 1 00 \x00 {} {}
|
||||
2 1 01 \x01 "\\u0001" 01
|
||||
3 1 3F \x3F "\\u003F" 3F
|
||||
4 1 7F \x7F "\\u007F" 7F
|
||||
5 1 80 \x80 "\\u0080" C280
|
||||
6 1 C3BF \xFF "\\u00FF" C3BF
|
||||
7 3 EFBFBD \xEF\xBF\xBD "\\uFFFD" {}
|
||||
} {
|
||||
|
||||
set hstr [ utf8_to_hstr $uval ]
|
||||
|
||||
ifcapable bloblit {
|
||||
if {$hstr != "%00"} {
|
||||
do_test badutf2-2.1.$i {
|
||||
set sql "SELECT '$hstr'=CAST(x'$uval' AS text) AS x;"
|
||||
set res [ sqlite3_exec db $sql ]
|
||||
lindex [ lindex $res 1] 1
|
||||
} {1}
|
||||
do_test badutf2-2.2.$i {
|
||||
set sql "SELECT CAST('$hstr' AS blob)=x'$uval' AS x;"
|
||||
set res [ sqlite3_exec db $sql ]
|
||||
lindex [ lindex $res 1] 1
|
||||
} {1}
|
||||
}
|
||||
do_test badutf2-2.3.$i {
|
||||
set sql "SELECT hex(CAST(x'$uval' AS text)) AS x;"
|
||||
set res [ sqlite3_exec db $sql ]
|
||||
lindex [ lindex $res 1] 1
|
||||
} $uval
|
||||
do_test badutf2-2.4.$i {
|
||||
set sql "SELECT hex(CAST(x'$uval' AS text)) AS x;"
|
||||
set res [ sqlite3_exec db $sql ]
|
||||
lindex [ lindex $res 1] 1
|
||||
} $uval
|
||||
}
|
||||
|
||||
if {$hstr != "%00"} {
|
||||
do_test badutf2-3.1.$i {
|
||||
set sql "SELECT hex('$hstr') AS x;"
|
||||
set res [ sqlite3_exec db $sql ]
|
||||
lindex [ lindex $res 1] 1
|
||||
} $uval
|
||||
}
|
||||
|
||||
do_test badutf2-4.1.$i {
|
||||
sqlite3_reset $S
|
||||
sqlite3_bind_text $S 1 $xstr $len
|
||||
sqlite3_step $S
|
||||
utf8_to_ustr2 [ sqlite3_column_text $S 0 ]
|
||||
} $ustr
|
||||
|
||||
do_test badutf2-5.1.$i {
|
||||
utf8_to_utf8 $uval
|
||||
} $u2u
|
||||
|
||||
}
|
||||
|
||||
do_test badutf2-4.2 {
|
||||
sqlite3_finalize $S
|
||||
} {SQLITE_OK}
|
||||
|
||||
|
||||
finish_test
|
@@ -14,6 +14,9 @@ set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix fts3fault2
|
||||
|
||||
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
|
||||
ifcapable !fts3 { finish_test ; return }
|
||||
|
||||
do_test 1.0 {
|
||||
execsql {
|
||||
CREATE VIRTUAL TABLE t1 USING fts4(x);
|
||||
|
@@ -117,8 +117,8 @@ proc do_faultsim_test {name args} {
|
||||
set DEFAULT(-prep) ""
|
||||
set DEFAULT(-body) ""
|
||||
set DEFAULT(-test) ""
|
||||
set DEFAULT(-install) ""
|
||||
set DEFAULT(-uninstall) ""
|
||||
set DEFAULT(-install) ""
|
||||
set DEFAULT(-uninstall) ""
|
||||
|
||||
fix_testname name
|
||||
|
||||
|
0
test/progress.test
Executable file → Normal file
0
test/progress.test
Executable file → Normal file
199
test/syscall.test
Normal file
199
test/syscall.test
Normal file
@@ -0,0 +1,199 @@
|
||||
# 2011 March 29
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
if {[llength [info commands test_syscall]]==0} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
set testprefix syscall
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests for the xSetSystemCall method.
|
||||
#
|
||||
do_test 1.1.1 {
|
||||
list [catch { test_syscall reset open } msg] $msg
|
||||
} {0 {}}
|
||||
do_test 1.1.2 {
|
||||
list [catch { test_syscall reset nosuchcall } msg] $msg
|
||||
} {1 SQLITE_NOTFOUND}
|
||||
do_test 1.1.3 {
|
||||
list [catch { test_syscall reset open } msg] $msg
|
||||
} {0 {}}
|
||||
do_test 1.1.4 {
|
||||
list [catch { test_syscall reset ""} msg] $msg
|
||||
} {1 SQLITE_NOTFOUND}
|
||||
|
||||
do_test 1.2 { test_syscall reset } {}
|
||||
|
||||
do_test 1.3.1 { test_syscall install {open getcwd access} } {}
|
||||
do_test 1.3.2 { test_syscall reset } {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests for the xGetSystemCall method.
|
||||
#
|
||||
do_test 2.1.1 { test_syscall exists open } 1
|
||||
do_test 2.1.2 { test_syscall exists nosuchcall } 0
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Tests for the xNextSystemCall method.
|
||||
#
|
||||
set syscall_list [list \
|
||||
open close access getcwd stat fstat ftruncate \
|
||||
fcntl read pread write pwrite fchmod \
|
||||
]
|
||||
if {[test_syscall exists fallocate]} {lappend syscall_list fallocate}
|
||||
do_test 3.1 { test_syscall list } $syscall_list
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test verifies that if a call to open() fails and errno is set to
|
||||
# EINTR, the call is retried. If it succeeds, execution continues as if
|
||||
# nothing happened.
|
||||
#
|
||||
test_syscall reset
|
||||
forcedelete test.db2
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
ATTACH 'test.db2' AS aux;
|
||||
CREATE TABLE aux.t2(x, y);
|
||||
INSERT INTO t2 VALUES(3, 4);
|
||||
}
|
||||
|
||||
db_save_and_close
|
||||
test_syscall install open
|
||||
foreach jrnl [list wal delete] {
|
||||
for {set i 1} {$i < 20} {incr i} {
|
||||
db_restore_and_reopen
|
||||
test_syscall fault $i 0
|
||||
test_syscall errno open EINTR
|
||||
|
||||
do_test 4.2.$jrnl.$i {
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux }
|
||||
execsql "PRAGMA main.journal_mode = $jrnl"
|
||||
execsql "PRAGMA aux.journal_mode = $jrnl"
|
||||
execsql {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(5, 6);
|
||||
INSERT INTO t2 VALUES(7, 8);
|
||||
COMMIT;
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
execsql { ATTACH 'test.db2' AS aux }
|
||||
execsql {
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}
|
||||
} {1 2 5 6 3 4 7 8}
|
||||
}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# This test verifies that closing database handles does not drop locks
|
||||
# held by other database handles in the same process on the same file.
|
||||
#
|
||||
# The os_unix.c module has to take precautions to prevent this as the
|
||||
# close() system call drops locks held by other file-descriptors on the
|
||||
# same file. From the Linux man page:
|
||||
#
|
||||
# close() closes a file descriptor, so that it no longer refers to any file
|
||||
# and may be reused. Any record locks (see fcntl(2)) held on the file it
|
||||
# was associated with, and owned by the process, are removed (regardless
|
||||
# of the file descriptor that was used to obtain the lock).
|
||||
#
|
||||
catch { db close }
|
||||
forcedelete test.db test.db2
|
||||
|
||||
do_multiclient_test tn {
|
||||
code1 {
|
||||
sqlite3 dbX1 test.db
|
||||
sqlite3 dbX2 test.db
|
||||
}
|
||||
|
||||
do_test syscall-5.$tn.1 {
|
||||
sql1 {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test syscall-5.$tn.2 { sql2 { SELECT * FROM t1 } } {1 2}
|
||||
do_test syscall-5.$tn.3 {
|
||||
csql2 { INSERT INTO t1 VALUES(5, 6) }
|
||||
} {1 {database is locked}}
|
||||
|
||||
do_test syscall-5.$tn.4 {
|
||||
code1 {
|
||||
dbX1 close
|
||||
dbX2 close
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test syscall-5.$tn.5 {
|
||||
csql2 { INSERT INTO t1 VALUES(5, 6) }
|
||||
} {1 {database is locked}}
|
||||
|
||||
do_test syscall-5.$tn.6 { sql1 { COMMIT } } {}
|
||||
|
||||
do_test syscall-5.$tn.7 {
|
||||
csql2 { INSERT INTO t1 VALUES(5, 6) }
|
||||
} {0 {}}
|
||||
}
|
||||
|
||||
catch {db close}
|
||||
do_test 6.1 {
|
||||
sqlite3 db1 test.db1
|
||||
sqlite3 db2 test.db2
|
||||
sqlite3 db3 test.db3
|
||||
sqlite3 dbM ""
|
||||
|
||||
db2 close
|
||||
db3 close
|
||||
dbM close
|
||||
db1 close
|
||||
} {}
|
||||
|
||||
do_test 6.2 {
|
||||
sqlite3 db test.db
|
||||
execsql {
|
||||
PRAGMA temp_store = file;
|
||||
|
||||
PRAGMA main.cache_size = 10;
|
||||
PRAGMA temp.cache_size = 10;
|
||||
CREATE TABLE temp.tt(a, b);
|
||||
INSERT INTO tt VALUES(randomblob(500), randomblob(600));
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
INSERT INTO tt SELECT randomblob(500), randomblob(600) FROM tt;
|
||||
}
|
||||
|
||||
db close
|
||||
} {}
|
||||
|
||||
|
||||
|
||||
finish_test
|
166
test/sysfault.test
Normal file
166
test/sysfault.test
Normal file
@@ -0,0 +1,166 @@
|
||||
# 2011 March 28
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
if {[llength [info commands test_syscall]]==0} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix sysfault
|
||||
|
||||
set FAULTSIM(vfsfault-transient) [list \
|
||||
-injectinstall vfsfault_install \
|
||||
-injectstart vfsfault_injectstart_t \
|
||||
-injectstop vfsfault_injectstop \
|
||||
-injecterrlist {} \
|
||||
-injectuninstall {test_syscall uninstall} \
|
||||
]
|
||||
set FAULTSIM(vfsfault-persistent) [list \
|
||||
-injectinstall vfsfault_install \
|
||||
-injectstart vfsfault_injectstart_p \
|
||||
-injectstop vfsfault_injectstop \
|
||||
-injecterrlist {} \
|
||||
-injectuninstall {test_syscall uninstall} \
|
||||
]
|
||||
|
||||
proc vfsfault_injectstart_t {iFail} { test_syscall fault $iFail 0 }
|
||||
proc vfsfault_injectstart_p {iFail} { test_syscall fault $iFail 1 }
|
||||
proc vfsfault_injectstop {} { test_syscall fault }
|
||||
|
||||
faultsim_save_and_close
|
||||
|
||||
|
||||
set open_and_write_body {
|
||||
sqlite3 db test.db
|
||||
db eval {
|
||||
CREATE TABLE t1(a, b);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
PRAGMA journal_mode = WAL;
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
SELECT * FROM t1;
|
||||
CREATE TEMP TABLE t2(x);
|
||||
INSERT INTO t2 VALUES('y');
|
||||
}
|
||||
}
|
||||
|
||||
proc vfsfault_install {} { test_syscall install {open getcwd} }
|
||||
do_faultsim_test 1 -faults vfsfault-* -prep {
|
||||
faultsim_restore
|
||||
} -body $open_and_write_body -test {
|
||||
faultsim_test_result {0 {wal 1 2 3 4}} \
|
||||
{1 {unable to open database file}} \
|
||||
{1 {attempt to write a readonly database}}
|
||||
}
|
||||
|
||||
# Errors in the fstat() function when opening and writing a file.
|
||||
#
|
||||
foreach {tn errno errlist} {
|
||||
1 ENOMEM {{disk I/O error}}
|
||||
2 EOVERFLOW {{disk I/O error} {large file support is disabled}}
|
||||
} {
|
||||
proc vfsfault_install {} { test_syscall install fstat }
|
||||
set errs [list]
|
||||
foreach e $errlist { lappend errs [list 1 $e] }
|
||||
do_faultsim_test 1.2.$tn -faults vfsfault-* -prep {
|
||||
faultsim_restore
|
||||
} -body "
|
||||
test_syscall errno fstat $errno
|
||||
$open_and_write_body
|
||||
" -test "
|
||||
faultsim_test_result {0 {wal 1 2 3 4}} $errs
|
||||
"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Check that a single EINTR error does not affect processing.
|
||||
#
|
||||
proc vfsfault_install {} {
|
||||
test_syscall reset
|
||||
test_syscall install {open ftruncate close}
|
||||
}
|
||||
|
||||
forcedelete test.db test.db2
|
||||
sqlite3 db test.db
|
||||
do_test 2.setup {
|
||||
execsql {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a));
|
||||
INSERT INTO t1 VALUES('abc', 'def', 'ghi');
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
CREATE TABLE aux.t2(x);
|
||||
INSERT INTO t2 VALUES(1);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
} {}
|
||||
|
||||
do_faultsim_test 2.1 -faults vfsfault-transient -prep {
|
||||
catch { db close }
|
||||
faultsim_restore
|
||||
} -body {
|
||||
test_syscall errno open EINTR
|
||||
test_syscall errno ftruncate EINTR
|
||||
test_syscall errno close EINTR
|
||||
|
||||
sqlite3 db test.db
|
||||
set res [db eval {
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
SELECT * FROM t1;
|
||||
PRAGMA journal_mode = truncate;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
|
||||
UPDATE t2 SET x = 2;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}]
|
||||
db close
|
||||
set res
|
||||
} -test {
|
||||
faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}}
|
||||
}
|
||||
|
||||
do_faultsim_test 2.2 -faults vfsfault-* -prep {
|
||||
catch { db close }
|
||||
faultsim_restore
|
||||
} -body {
|
||||
sqlite3 db test.db
|
||||
set res [db eval {
|
||||
ATTACH 'test.db2' AS 'aux';
|
||||
SELECT * FROM t1;
|
||||
PRAGMA journal_mode = truncate;
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES('jkl', 'mno', 'pqr');
|
||||
UPDATE t2 SET x = 2;
|
||||
COMMIT;
|
||||
SELECT * FROM t1;
|
||||
SELECT * FROM t2;
|
||||
}]
|
||||
db close
|
||||
set res
|
||||
} -test {
|
||||
faultsim_test_result {0 {abc def ghi truncate abc def ghi jkl mno pqr 2}} \
|
||||
{1 {unable to open database file}} \
|
||||
{1 {unable to open database: test.db2}} \
|
||||
{1 {attempt to write a readonly database}} \
|
||||
{1 {disk I/O error}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
|
||||
finish_test
|
||||
|
@@ -231,6 +231,14 @@ ifcapable schema_pragmas {
|
||||
} {0 1 1 user_version 0}
|
||||
}
|
||||
|
||||
# do_malloc_test closes and deletes the usual db connections and files on
|
||||
# each iteration. $::dbx is a seperate connection, and on Windows, will
|
||||
# cause the file deletion of test.db to fail, so we move the close of $::dbx
|
||||
# up to here before the do_malloc_test.
|
||||
do_test tableapi-99.0 {
|
||||
sqlite3_close $::dbx
|
||||
} {SQLITE_OK}
|
||||
|
||||
ifcapable memdebug {
|
||||
do_malloc_test tableapi-7 -sqlprep {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
@@ -245,8 +253,4 @@ ifcapable memdebug {
|
||||
}
|
||||
}
|
||||
|
||||
do_test tableapi-99.0 {
|
||||
sqlite3_close $::dbx
|
||||
} {SQLITE_OK}
|
||||
|
||||
finish_test
|
||||
|
Reference in New Issue
Block a user