1
0
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:
drh
2011-03-30 02:03:12 +00:00
24 changed files with 1222 additions and 78 deletions

0
install-sh Normal file → Executable file
View File

View File

@@ -254,6 +254,7 @@ TESTSRC = \
$(TOP)/src/test_server.c \ $(TOP)/src/test_server.c \
$(TOP)/src/test_stat.c \ $(TOP)/src/test_stat.c \
$(TOP)/src/test_superlock.c \ $(TOP)/src/test_superlock.c \
$(TOP)/src/test_syscall.c \
$(TOP)/src/test_tclvar.c \ $(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \ $(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \ $(TOP)/src/test_vfs.c \

View File

@@ -1,5 +1,5 @@
C Improve\scoverage\sof\ssession\smodule\sa\sbit\smore. C Merge\sin\sall\sthe\slatest\schanges\sfrom\strunk.
D 2011-03-25T19:06:10 D 2011-03-30T02:03:12.567
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 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.c 9be8ccee4248681700659b89a81ae5c6cb8afacc
F ext/session/sqlite3session.h f284bac51c12de0e0096fc986e61f5ae6b9e5be5 F ext/session/sqlite3session.h f284bac51c12de0e0096fc986e61f5ae6b9e5be5
F ext/session/test_session.c f8fdf5c110898b2bbc20c475fca879664c77fb5a F ext/session/test_session.c f8fdf5c110898b2bbc20c475fca879664c77fb5a
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7 F main.mk e283752f215b7055cdc48399da82033b67024e42
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -127,13 +127,13 @@ F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07 F src/analyze.c a038162344265ac21dfb24b3fcc06c666ebb9c07
F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877 F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c 43302cc4f3de6479b90fa6bb271b65d86333d00e F src/btree.c 2b9c81ff64da339a67dda4f94c0d763627be0b67
F src/btree.h e2f2cd9933bf30724f53ffa12c4c5a3a864bbd6e F src/btree.h 8d36f774ec4b1d0027b8966f8c03d9a72a518c14
F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4 F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
F src/build.c 821d4b3c6b1da068a4eb1e9c8c414b75612d34c2 F src/build.c 6c490fe14dedb094a202f559e3b29a276abffcf8
F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc F src/callback.c 5069f224882cbdccd559f591271d28d7f37745bc
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01 F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01
@@ -171,7 +171,7 @@ F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9 F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf 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/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1 F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1 F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
@@ -187,13 +187,13 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c d24406c45dd2442eb2eeaac413439066b149c944 F src/select.c d24406c45dd2442eb2eeaac413439066b149c944
F src/shell.c 9dc0b4bb59290c0a35256d278cab0f314987ad6a F src/shell.c 9dc0b4bb59290c0a35256d278cab0f314987ad6a
F src/sqlite.h.in 846a91e163497b596b5bbebd26477eaf234eb1c0 F src/sqlite.h.in 73512de44f0d3563dd24be2e701542e52c7efe25
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h 7c11f9a648cf82e87330fd2185fcaa1f7c46dfba F src/sqliteInt.h 7c11f9a648cf82e87330fd2185fcaa1f7c46dfba
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 78713534e628ea92b032bfa20ea8a1afc6cdb124 F src/tclsqlite.c c233c25153b6fa3b511bc65df352cb8f97a0f81d
F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290 F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
@@ -229,26 +229,27 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6 F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c F src/test_stat.c f682704b5d1ba8e1d4e7e882a6d7922e2dcf066c
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c d12e8cd163cd33b66d0a3d1b8daaf136d09d65c2
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0 F src/test_thread.c bedd05cad673dba53326f3aa468cc803038896c0
F src/test_vfs.c 2ed8853c1e51ac6f9ea091f7ce4e0d618bba8b86 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/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080 F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
F src/trigger.c ec4813709e990a169b6923293e839fa5dfd64282 F src/trigger.c ec4813709e990a169b6923293e839fa5dfd64282
F src/update.c f81e9b326cafba3fbe493141e396f3bbfba1d99b F src/update.c f81e9b326cafba3fbe493141e396f3bbfba1d99b
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/utf.c d83650c3ea08f7407bd9d0839d9885241c209c60
F src/util.c cd997077bad039efc0597eb027c929658f93c018 F src/util.c cd997077bad039efc0597eb027c929658f93c018
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
F src/vdbe.c c90edafd941481506f001b17cd8523683fdac853 F src/vdbe.c 175a42d0f12b92093a7335402dbb46bfe7e360b0
F src/vdbe.h edef9c4f0be83e1f1dccd049da37b40e021b63d9 F src/vdbe.h edef9c4f0be83e1f1dccd049da37b40e021b63d9
F src/vdbeInt.h b6748a8ac9be169d83585a0f5daf747863c6b8db F src/vdbeInt.h b6748a8ac9be169d83585a0f5daf747863c6b8db
F src/vdbeapi.c e472b3e5985175e948e70025cb3bffa8a2e185c8 F src/vdbeapi.c e472b3e5985175e948e70025cb3bffa8a2e185c8
F src/vdbeaux.c af3be34b1980e428972ea11ef3a1d88acf8f2b9d F src/vdbeaux.c 051a1609e578418d1bfc6d2420b8eb412a7aea97
F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562 F src/vdbeblob.c c3ccb7c8732858c680f442932e66ad06bb036562
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5 F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30 F src/vtab.c e1edca38c4c4310710635bb91bb3c87fdf60f21d
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794 F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840 F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
@@ -290,6 +291,7 @@ F test/backup2.test b7c69f937c912e85ac8a5dbd1e1cf290302b2d49
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38 F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
F test/badutf2.test a47fda0d986d5325aa0ec2a0ebdd2d68db45e623
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070 F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103 F test/bigfile.test a8ec8073a20207456dab01a29ad9cde42b0dd103
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747 F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
@@ -466,7 +468,7 @@ F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246 F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
F test/fts3fault2.test f275554f4a4fc7abf71e2975a9d6f4693f390526 F test/fts3fault2.test dc96203af6ba31ce20163fc35460e1556e8edf4d
F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b F test/fts3malloc.test 9c8cc3f885bb4dfc66d0460c52f68f45e4710d1b
F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba F test/fts3matchinfo.test cc0b009edbbf575283d5fdb53271179e0d8019ba
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844 F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
@@ -567,7 +569,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6 F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 660b82ab528521cc4a48ff6df05ca3b6a00d47c5 F test/malloc_common.tcl 50d0ed21eed0ae9548b58935bd29ac89a05a54fa
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498 F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
@@ -611,7 +613,7 @@ F test/permutations.test 1e35edce72e6d9e2e392420caed18652a97b1a95
F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850 F test/pragma.test fdfc09067ea104a0c247a1a79d8093b56656f850
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47 F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301 x F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
F test/quota.test ddafe133653093eb9a99ccd6264884ae43f9c9b8 F test/quota.test ddafe133653093eb9a99ccd6264884ae43f9c9b8
@@ -680,8 +682,10 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082 F test/superlock.test 5d7a4954b0059c903f82c7b67867bc5451a7c082
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3 F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
F test/syscall.test 125d9781d914c408e8629053b5f914dc920ab3eb
F test/sysfault.test be42aa42f89a82305cf3807047d419595e430480
F test/table.test 04ba066432430657712d167ebf28080fe878d305 F test/table.test 04ba066432430657712d167ebf28080fe878d305
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a F test/tclsqlite.test 1ce9b6340d6d412420634e129a2e3722c651056a
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
@@ -925,7 +929,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 666123c8d07be87d477e67b1cebef2b0fba5b4bc P 4255a9f609c4fd43582a0874143eabe211199726 3d2de011814002e2e25b7645f94ff8fc7aab9cdd
R 06396f39a2dba603f238d63a566a7e13 R 48b479c7a408c0c8015c6f938b7e92a4
U dan U drh
Z 44bcd7637527a5a2be65b60012fc28ed Z 1cd943e96dc4b8cfc7720b21a63156f8

View File

@@ -1 +1 @@
4255a9f609c4fd43582a0874143eabe211199726 b11d941e92897663da46160185e6e305d4e28fe6

View File

@@ -488,7 +488,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
/* Finish committing the transaction to the destination database. */ /* Finish committing the transaction to the destination database. */
if( SQLITE_OK==rc if( SQLITE_OK==rc
&& SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest)) && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0))
){ ){
rc = SQLITE_DONE; rc = SQLITE_DONE;
} }
@@ -502,7 +502,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( bCloseTrans ){ if( bCloseTrans ){
TESTONLY( int rc2 ); TESTONLY( int rc2 );
TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0);
TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc); TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0);
assert( rc2==SQLITE_OK ); assert( rc2==SQLITE_OK );
} }

View File

@@ -3160,10 +3160,21 @@ static void btreeEndTransaction(Btree *p){
** the rollback journal (which causes the transaction to commit) and ** the rollback journal (which causes the transaction to commit) and
** drop locks. ** 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 ** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock. ** 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; if( p->inTrans==TRANS_NONE ) return SQLITE_OK;
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
@@ -3178,7 +3189,7 @@ int sqlite3BtreeCommitPhaseTwo(Btree *p){
assert( pBt->inTransaction==TRANS_WRITE ); assert( pBt->inTransaction==TRANS_WRITE );
assert( pBt->nTransaction>0 ); assert( pBt->nTransaction>0 );
rc = sqlite3PagerCommitPhaseTwo(pBt->pPager); rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK && bCleanup==0 ){
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return rc; return rc;
} }
@@ -3198,7 +3209,7 @@ int sqlite3BtreeCommit(Btree *p){
sqlite3BtreeEnter(p); sqlite3BtreeEnter(p);
rc = sqlite3BtreeCommitPhaseOne(p, 0); rc = sqlite3BtreeCommitPhaseOne(p, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3BtreeCommitPhaseTwo(p); rc = sqlite3BtreeCommitPhaseTwo(p, 0);
} }
sqlite3BtreeLeave(p); sqlite3BtreeLeave(p);
return rc; return rc;

View File

@@ -87,7 +87,7 @@ int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *); int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int); int sqlite3BtreeBeginTrans(Btree*,int);
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster); int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
int sqlite3BtreeCommitPhaseTwo(Btree*); int sqlite3BtreeCommitPhaseTwo(Btree*, int);
int sqlite3BtreeCommit(Btree*); int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*); int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*,int); int sqlite3BtreeBeginStmt(Btree*,int);

View File

@@ -368,7 +368,7 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){
len = sqlite3Strlen30(zIdxName); len = sqlite3Strlen30(zIdxName);
pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0); pIndex = sqlite3HashInsert(pHash, zIdxName, len, 0);
if( pIndex ){ if( ALWAYS(pIndex) ){
if( pIndex->pTable->pIndex==pIndex ){ if( pIndex->pTable->pIndex==pIndex ){
pIndex->pTable->pIndex = pIndex->pNext; pIndex->pTable->pIndex = pIndex->pNext;
}else{ }else{

View File

@@ -371,7 +371,7 @@ static struct unix_syscall {
#else #else
{ "fallocate", (sqlite3_syscall_ptr)0, 0 }, { "fallocate", (sqlite3_syscall_ptr)0, 0 },
#endif #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 */ }; /* End of the overrideable system calls */
@@ -444,18 +444,16 @@ static sqlite3_syscall_ptr unixGetSystemCall(
** system call. ** system call.
*/ */
static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
unsigned int i; int i = -1;
UNUSED_PARAMETER(p); UNUSED_PARAMETER(p);
if( zName==0 ){ if( zName ){
i = -1; for(i=0; i<ArraySize(aSyscall)-1; i++){
}else{ if( strcmp(zName, aSyscall[i].zName)==0 ) break;
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0])-1; i++){
if( strcmp(zName, aSyscall[0].zName)==0 ) break;
} }
} }
for(i++; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){ for(i++; i<ArraySize(aSyscall); i++){
if( aSyscall[0].pCurrent!=0 ) return aSyscall[0].zName; if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
} }
return 0; return 0;
} }
@@ -3380,8 +3378,8 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
int rc; int rc;
do{ do{
rc = osFallocate(pFile->.h, buf.st_size, nSize-buf.st_size; rc = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
}while( rc<0 && errno=EINTR ); }while( rc<0 && errno==EINTR );
if( rc ) return SQLITE_IOERR_WRITE; if( rc ) return SQLITE_IOERR_WRITE;
#else #else
/* If the OS does not have posix_fallocate(), fake it. First use /* If the OS does not have posix_fallocate(), fake it. First use

View File

@@ -2975,7 +2975,9 @@ int sqlite3_column_count(sqlite3_stmt *pStmt);
** column number. ^The leftmost column is number 0. ** column number. ^The leftmost column is number 0.
** **
** ^The returned string pointer is valid until either the [prepared statement] ** ^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. ** sqlite3_column_name() or sqlite3_column_name16() on the same column.
** **
** ^If sqlite3_malloc() fails during the processing of either routine ** ^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 database name, the _table_ routines return the table name, and
** the origin_ routines return the column name. ** the origin_ routines return the column name.
** ^The returned string is valid until the [prepared statement] is destroyed ** ^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. ** again in a different encoding.
** **
** ^The names returned are the original un-aliased names of the ** ^The names returned are the original un-aliased names of the

View File

@@ -3719,10 +3719,10 @@ static void init_all(Tcl_Interp *interp){
extern int Sqlitequota_Init(Tcl_Interp*); extern int Sqlitequota_Init(Tcl_Interp*);
extern int Sqlitemultiplex_Init(Tcl_Interp*); extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*); extern int SqliteSuperlock_Init(Tcl_Interp*);
extern int SqlitetestSyscall_Init(Tcl_Interp*);
#ifdef SQLITE_ENABLE_SESSION #ifdef SQLITE_ENABLE_SESSION
extern int TestSession_Init(Tcl_Interp*); extern int TestSession_Init(Tcl_Interp*);
#endif #endif
#ifdef SQLITE_ENABLE_ZIPVFS #ifdef SQLITE_ENABLE_ZIPVFS
extern int Zipvfs_Init(Tcl_Interp*); extern int Zipvfs_Init(Tcl_Interp*);
Zipvfs_Init(interp); Zipvfs_Init(interp);
@@ -3759,6 +3759,7 @@ static void init_all(Tcl_Interp *interp){
Sqlitequota_Init(interp); Sqlitequota_Init(interp);
Sqlitemultiplex_Init(interp); Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp); SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp);
#ifdef SQLITE_ENABLE_SESSION #ifdef SQLITE_ENABLE_SESSION
TestSession_Init(interp); TestSession_Init(interp);
#endif #endif

642
src/test_syscall.c Normal file
View 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

View File

@@ -77,8 +77,8 @@ static int vfstraceSleep(sqlite3_vfs*, int microseconds);
static int vfstraceCurrentTime(sqlite3_vfs*, double*); static int vfstraceCurrentTime(sqlite3_vfs*, double*);
static int vfstraceGetLastError(sqlite3_vfs*, int, char*); static int vfstraceGetLastError(sqlite3_vfs*, int, char*);
static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); static int vfstraceCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
static int vfstraceSetSystemCall(sqlite3_vfs*, const char *zName, void *pFunc); static int vfstraceSetSystemCall(sqlite3_vfs*,const char*, sqlite3_syscall_ptr);
static void *vfstraceGetSystemCall(sqlite3_vfs*, const char *zName); static sqlite3_syscall_ptr vfstraceGetSystemCall(sqlite3_vfs*, const char *);
static const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName); 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( static int vfstraceSetSystemCall(
sqlite3_vfs *pVfs, sqlite3_vfs *pVfs,
const char *zName, const char *zName,
void *pFunc sqlite3_syscall_ptr pFunc
){ ){
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData; vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
sqlite3_vfs *pRoot = pInfo->pRootVfs; sqlite3_vfs *pRoot = pInfo->pRootVfs;
return pRoot->xSetSystemCall(pRoot, zName, pFunc); 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; vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
sqlite3_vfs *pRoot = pInfo->pRootVfs; sqlite3_vfs *pRoot = pInfo->pRootVfs;
return pRoot->xGetSystemCall(pRoot, zName); return pRoot->xGetSystemCall(pRoot, zName);

View File

@@ -167,7 +167,7 @@ int sqlite3Utf8Read(
const unsigned char *zIn, /* First byte of UTF-8 character */ const unsigned char *zIn, /* First byte of UTF-8 character */
const unsigned char **pzNext /* Write first byte past UTF-8 char here */ 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. /* Same as READ_UTF8() above but without the zTerm parameter.
** For this routine, we assume the UTF8 string is always zero-terminated. ** 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 ** This has the effect of making sure that the string is well-formed
** UTF-8. Miscoded characters are removed. ** UTF-8. Miscoded characters are removed.
** **
** The translation is done in-place (since it is impossible for the ** The translation is done in-place and aborted if the output
** correct UTF-8 encoding to be longer than a malformed encoding). ** overruns the input.
*/ */
int sqlite3Utf8To8(unsigned char *zIn){ int sqlite3Utf8To8(unsigned char *zIn){
unsigned char *zOut = zIn; unsigned char *zOut = zIn;
unsigned char *zStart = zIn; unsigned char *zStart = zIn;
u32 c; u32 c;
while( zIn[0] ){ while( zIn[0] && zOut<=zIn ){
c = sqlite3Utf8Read(zIn, (const u8**)&zIn); c = sqlite3Utf8Read(zIn, (const u8**)&zIn);
if( c!=0xfffd ){ if( c!=0xfffd ){
WRITE_UTF8(zOut, c); WRITE_UTF8(zOut, c);

View File

@@ -4646,14 +4646,10 @@ case OP_CreateTable: { /* out2-prerelease */
break; break;
} }
/* Opcode: ParseSchema P1 P2 * P4 * /* Opcode: ParseSchema P1 * * P4 *
** **
** Read and parse all entries from the SQLITE_MASTER table of database P1 ** 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 ** that match the WHERE clause P4.
** 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.
** **
** This opcode invokes the parser to create a new virtual machine, ** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a re-entrant opcode. ** then runs the new virtual machine. It is thus a re-entrant opcode.
@@ -4667,14 +4663,7 @@ case OP_ParseSchema: {
iDb = pOp->p1; iDb = pOp->p1;
assert( iDb>=0 && iDb<db->nDb ); assert( iDb>=0 && iDb<db->nDb );
/* If pOp->p2 is 0, then this opcode is being executed to read a /* Although the mutex on the BtShared object that corresponds to
** 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
** database iDb (the database containing the sqlite_master table ** database iDb (the database containing the sqlite_master table
** read by this instruction) is currently held, it is necessary to ** read by this instruction) is currently held, it is necessary to
** obtain the mutexes on all attached databases before checking if ** obtain the mutexes on all attached databases before checking if
@@ -4690,7 +4679,7 @@ case OP_ParseSchema: {
*/ */
assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); assert( sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) );
sqlite3BtreeEnterAll(db); sqlite3BtreeEnterAll(db);
if( pOp->p2 || DbHasProperty(db, iDb, DB_SchemaLoaded) ){ if( ALWAYS(DbHasProperty(db, iDb, DB_SchemaLoaded)) ){
zMaster = SCHEMA_TABLE(iDb); zMaster = SCHEMA_TABLE(iDb);
initData.db = db; initData.db = db;
initData.iDb = pOp->p1; initData.iDb = pOp->p1;

View File

@@ -1704,7 +1704,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt ){ if( pBt ){
rc = sqlite3BtreeCommitPhaseTwo(pBt); rc = sqlite3BtreeCommitPhaseTwo(pBt, 0);
} }
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@@ -1836,7 +1836,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
for(i=0; i<db->nDb; i++){ for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt; Btree *pBt = db->aDb[i].pBt;
if( pBt ){ if( pBt ){
sqlite3BtreeCommitPhaseTwo(pBt); sqlite3BtreeCommitPhaseTwo(pBt, 1);
} }
} }
sqlite3EndBenignMalloc(); sqlite3EndBenignMalloc();

View File

@@ -372,7 +372,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp2(v, OP_Expire, 0, 0); sqlite3VdbeAddOp2(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf(db, "name='%q' AND type='table'", pTab->zName); 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, sqlite3VdbeAddOp4(v, OP_VCreate, iDb, 0, 0,
pTab->zName, sqlite3Strlen30(pTab->zName) + 1); pTab->zName, sqlite3Strlen30(pTab->zName) + 1);
} }

119
test/badutf2.test Normal file
View 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

View File

@@ -14,6 +14,9 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
set ::testprefix fts3fault2 set ::testprefix fts3fault2
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }
do_test 1.0 { do_test 1.0 {
execsql { execsql {
CREATE VIRTUAL TABLE t1 USING fts4(x); CREATE VIRTUAL TABLE t1 USING fts4(x);

View File

@@ -117,8 +117,8 @@ proc do_faultsim_test {name args} {
set DEFAULT(-prep) "" set DEFAULT(-prep) ""
set DEFAULT(-body) "" set DEFAULT(-body) ""
set DEFAULT(-test) "" set DEFAULT(-test) ""
set DEFAULT(-install) "" set DEFAULT(-install) ""
set DEFAULT(-uninstall) "" set DEFAULT(-uninstall) ""
fix_testname name fix_testname name

0
test/progress.test Executable file → Normal file
View File

199
test/syscall.test Normal file
View 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
View 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

View File

@@ -231,6 +231,14 @@ ifcapable schema_pragmas {
} {0 1 1 user_version 0} } {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 { ifcapable memdebug {
do_malloc_test tableapi-7 -sqlprep { do_malloc_test tableapi-7 -sqlprep {
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
@@ -245,8 +253,4 @@ ifcapable memdebug {
} }
} }
do_test tableapi-99.0 {
sqlite3_close $::dbx
} {SQLITE_OK}
finish_test finish_test