mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-10 01:02:56 +03:00
Merge all the latest trunk enhancements into the sessions branch.
FossilOrigin-Name: 94fd5bb6da5ef4d850c2ed4ad38afabc5569dae6
This commit is contained in:
@@ -3133,7 +3133,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
|
||||
int jj;
|
||||
|
||||
nodeGetCell(&tree, &node, ii, &cell);
|
||||
sqlite3_snprintf(512-nCell,&zCell[nCell],"%d", cell.iRowid);
|
||||
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
|
||||
nCell = strlen(zCell);
|
||||
for(jj=0; jj<tree.nDim*2; jj++){
|
||||
sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f);
|
||||
|
34
ext/rtree/rtreeB.test
Normal file
34
ext/rtree/rtreeB.test
Normal file
@@ -0,0 +1,34 @@
|
||||
# 2011 March 2
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
# Make sure the rtreenode() testing function can handle entries with
|
||||
# 64-bit rowids.
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
ifcapable !rtree { finish_test ; return }
|
||||
|
||||
do_test rtreeB-1.1 {
|
||||
db eval {
|
||||
CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
|
||||
INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
|
||||
INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
|
||||
INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
|
||||
INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
|
||||
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
|
||||
SELECT rtreenode(2, data) FROM t1_node;
|
||||
}
|
||||
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
|
||||
|
||||
|
||||
finish_test
|
0
install-sh
Normal file → Executable file
0
install-sh
Normal file → Executable file
103
manifest
103
manifest
@@ -1,5 +1,8 @@
|
||||
C Change\sto\sthe\ssession\smodule\sto\suse\suser-defined\sprimary\skeys\sinstead\sof\srowids\swhen\scollecting\schanges.
|
||||
D 2011-03-17T19:20:27
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Merge\sall\sthe\slatest\strunk\senhancements\sinto\sthe\ssessions\sbranch.
|
||||
D 2011-03-18T12:35:36.113
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@@ -81,7 +84,7 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
|
||||
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 05b293c85403cf39bb5af0e7c010b0cafeab5e47
|
||||
F ext/rtree/rtree.c 115b499415ddef9be75615ced99b11232826e64d
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test dbd4250ac0ad367a262eb9676f7e3080b0368206
|
||||
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
|
||||
@@ -93,6 +96,7 @@ F ext/rtree/rtree7.test bcb647b42920b3b5d025846689147778485cc318
|
||||
F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d
|
||||
F ext/rtree/rtree9.test df9843d1a9195249c8d3b4ea6aedda2d5c73e9c2
|
||||
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
|
||||
F ext/rtree/rtreeB.test b1916a9cecb86b02529c4cc5a546e8d6e7ff10da
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
|
||||
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0
|
||||
@@ -101,7 +105,7 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F ext/session/sqlite3session.c 4183792547af5b5d3ec1c8a3f858beb172682503
|
||||
F ext/session/sqlite3session.h 63045871564085669b5cb1fb92e6efc2e1b1120a
|
||||
F ext/session/test_session.c 2559ef68e421c7fb83e2c19ef08a17343b70d535
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F main.mk ae0868e05c76eaa8a0ae3d6927a949b1c8e810d7
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
@@ -123,66 +127,66 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 6728d6d48d55b449af76a3e51c0808849cb32a2e
|
||||
F src/bitvec.c af50f1c8c0ff54d6bdb7a80e2fceca5a93670bef
|
||||
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
|
||||
F src/btree.c ca9f44866554f634c12806635bc5b063d70bca9b
|
||||
F src/btree.c 43302cc4f3de6479b90fa6bb271b65d86333d00e
|
||||
F src/btree.h e2f2cd9933bf30724f53ffa12c4c5a3a864bbd6e
|
||||
F src/btreeInt.h 20f73dc93b1eeb83afd7259fbc6bd7dcf2df7fe4
|
||||
F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
|
||||
F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 7deec4534f3b5a0c3b4a4cbadf809d321f64f9c4
|
||||
F src/ctime.c 52ff72f966cee3087e0138a3ec69371c22be3c01
|
||||
F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
|
||||
F src/delete.c 3c0925e958a77804a004222baa1a2a8ad855306b
|
||||
F src/expr.c 8e2c607b3be87a35c75a1f5dac50c10666b083c0
|
||||
F src/expr.c 00817c672af554321fd67c44325afd7cef0e4648
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a
|
||||
F src/func.c cb41f614edc43b00bfeb030f9768e80eaff47edd
|
||||
F src/fkey.c 418b840007c873975fd0d071746d952f8bca20ce
|
||||
F src/func.c 3a8cb2fb2de3e3aed7f39106daf4878d9d17fcce
|
||||
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
|
||||
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
|
||||
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c c56a64b1488921794c3855d54acfe4674c7cea0c
|
||||
F src/insert.c b0d4150ae6d6fae7c3e8b69b65bcf37988d80ac0
|
||||
F src/journal.c 552839e54d1bf76fb8f7abe51868b66acacf6a0e
|
||||
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
|
||||
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
|
||||
F src/loadext.c 8af9fcc75708d60b88636ccba38b4a7b3c155c3e
|
||||
F src/main.c 9ab948225b8c362cdd6902c447abbf218607e0f3
|
||||
F src/main.c 3c09359bbc8d6eae238a77e6a5cb2cbf1a41edb5
|
||||
F src/malloc.c 92d59a007d7a42857d4e9454aa25b6b703286be1
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 00bd8265c81abb665c48fea1e0c234eb3b922206
|
||||
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
|
||||
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
|
||||
F src/mem5.c 6fe00f46997bebb690397cb029719f711e7640e3
|
||||
F src/mem5.c 72e0bc40f535ac38a11712aed01d0014f9300732
|
||||
F src/memjournal.c 0ebce851677a7ac035ba1512a7e65851b34530c6
|
||||
F src/mutex.c 6949180803ff05a7d0e2b9334a95b4fb5a00e23f
|
||||
F src/mutex.h fe2ef5e1c4dae531d5a544f9241f19c56d26803d
|
||||
F src/mutex_noop.c d5cfbca87168c661a0b118cd8e329a908e453151
|
||||
F src/mutex_os2.c 6a62583e374ba3ac1a3fcc0da2bfdac7d3942689
|
||||
F src/mutex_os2.c f5d09e85b914643c230aa97db709fc0db370d93c
|
||||
F src/mutex_unix.c b4f4e923bb8de93ec3f251fadb50855f23df9579
|
||||
F src/mutex_w32.c 3ade5ae71449d1d023f0ebb3184c2ae6aa9307e4
|
||||
F src/mutex_w32.c 5e54f3ba275bcb5d00248b8c23107df2e2f73e33
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 22ac61d06e72a0dac900400147333b07b13d8e1d
|
||||
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
|
||||
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 2e452c9f2ca507623ad351c33a8a8b27849b1863
|
||||
F src/os_unix.c 64a2e0ebbb19765f97993b3920f795e6f38fd923
|
||||
F src/os_win.c 9abdcdd925416d854eabb0996c96debd92abfef5
|
||||
F src/os_os2.c 2596fd2d5d0976c6c0c628d0c3c7c4e7a724f4cf
|
||||
F src/os_unix.c 919972244dd7267815f9fc176b662390ff0b2348
|
||||
F src/os_win.c 24d72407a90551969744cf9bcbb1b4c72c5fa845
|
||||
F src/pager.c 6aa906b60a59664ba58d3f746164bb010d407ce1
|
||||
F src/pager.h 3f8c783de1d4706b40b1ac15b64f5f896bcc78d1
|
||||
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
|
||||
F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
|
||||
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
|
||||
F src/pcache1.c d548e31beafa792d1994b663a29a5303569efc4e
|
||||
F src/pragma.c a83f320497aee18eda60fc8d854df5897906c2b1
|
||||
F src/prepare.c 395b3fab1b93f45b6aa194b23ebc201221c47b99
|
||||
F src/printf.c df2ff3bb5409e8958136933342c46464fbd017e7
|
||||
F src/pragma.c 4221eb822d7cdb1fb69be555b189e15e5a24b6b5
|
||||
F src/prepare.c eb4944d9f7bfa13eb42a7416ed9aaed4de4d0bf3
|
||||
F src/printf.c 585a36b6a963df832cfb69505afa3a34ed5ef8a1
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c d24406c45dd2442eb2eeaac413439066b149c944
|
||||
F src/shell.c 649c51979812f77f97507024a4cea480c6862b8b
|
||||
F src/sqlite.h.in 992c54d9bd451a041fb0b74fb5cd3b14db98e544
|
||||
F src/shell.c 4a5e0ad845475c84881f0b25b1abba2ddaab0a72
|
||||
F src/sqlite.h.in 208dc372c9b8d89ca962babcb7cb0c1b16d32bc4
|
||||
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
|
||||
F src/sqliteInt.h db209477de559911d7f14c1d208cbf2bc46e9224
|
||||
F src/sqliteInt.h d65b832eb82bd3f04cd27a750698c7f4b3d9273a
|
||||
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
|
||||
F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@@ -200,7 +204,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
|
||||
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
|
||||
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
|
||||
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
|
||||
F src/test_config.c 9f025a7f3686c94e82dc6d6bd3cbf0f89cd67487
|
||||
F src/test_config.c 62f0f8f934b1d5c7e4cd4f506ae453a1117b47d7
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
|
||||
@@ -225,26 +229,27 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
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_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
|
||||
F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
|
||||
F src/update.c 18a862e3e08377a5afb26d6f16182a8f700a1ca7
|
||||
F src/trigger.c 95d2ff4b2996fabe886c9764b5978980e29f4afa
|
||||
F src/update.c aa39db6c39a1e234e8badf49768e1389dbb34650
|
||||
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
|
||||
F src/util.c ab1c92426494f499f42b9e307537b03e923d75c1
|
||||
F src/util.c cd997077bad039efc0597eb027c929658f93c018
|
||||
F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
|
||||
F src/vdbe.c fbf11bd681fd2313aaf59fb2fd7f02cd8324a88a
|
||||
F src/vdbe.c 94cd191b1b20b0124e09b056bbce3d09f79821b3
|
||||
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
|
||||
F src/vdbeInt.h 20d13da932eed0667a2e2383a9cb0f80099a5fd3
|
||||
F src/vdbeapi.c 3066456f64fb10c9c5151c684b5f5e8d67a5f4f2
|
||||
F src/vdbeaux.c 896844f9bf663202b3afa8c139e2caddcf855765
|
||||
F src/vdbeapi.c 988ee9420acf8c130d644e6d7282893efe927bbd
|
||||
F src/vdbeaux.c ce48afec3f218b755f7b0ef1bef54a4be44cd833
|
||||
F src/vdbeblob.c 18955f0ee6b133cd08e1592010cb9a6b11e9984c
|
||||
F src/vdbemem.c 0fa2ed786cd207d5b988afef3562a8e663a75b50
|
||||
F src/vdbemem.c 0498796b6ffbe45e32960d6a1f5adfb6e419883b
|
||||
F src/vdbetrace.c 3ba13bc32bdf16d2bdea523245fd16736bed67b5
|
||||
F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
|
||||
F src/wal.c 5386fb5e13c2daa8ab9062597fdc17bd849da371
|
||||
F src/wal.c 7334009b396285b658a95a3b6bc6d2b016a1f794
|
||||
F src/wal.h 7a5fbb00114b7f2cd40c7e1003d4c41ce9d26840
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c bf8c0f584a2c9becb9110c37e151f9d4f73fbf7e
|
||||
F src/where.c a6e89fe7e56ab7e633be6fdebdddd857e9e5bc99
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
F test/all.test 51756962d522e474338e9b2ebb26e7364d4aa125
|
||||
@@ -257,7 +262,8 @@ F test/analyze.test c1eb87067fc16ece7c07e823d6395fd831b270c5
|
||||
F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3
|
||||
F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b
|
||||
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
|
||||
F test/analyze5.test 0618d2fe8982a5dae1d4e92152acc8ecbaf52be2
|
||||
F test/analyze5.test adc89b92fc9fee5ca1cb0bc8512f3206ad0fe5aa
|
||||
F test/analyze6.test 1ba1aea8fad25a77ffd71f24522d1bb9ecc949fc
|
||||
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
|
||||
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
|
||||
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
|
||||
@@ -381,7 +387,7 @@ F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
|
||||
F test/exclusive2.test 343d55130c12c67b8bf10407acec043a6c26c86b
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/expr.test 620a636cf7b7d4e5834a0b9d83a4da372e24a7b7
|
||||
F test/expr.test 19e8ac40313e2282a47b586d11c4892040990d3a
|
||||
F test/fallocate.test 43dc34b8c24be6baffadc3b4401ee15710ce83c6
|
||||
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
|
||||
F test/filefmt.test f178cfc29501a14565954c961b226e61877dd32c
|
||||
@@ -488,7 +494,7 @@ F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0
|
||||
F test/incrvacuum.test 453d1e490d8f5ad2c9b3a54282a0690d6ae56462
|
||||
F test/incrvacuum2.test 9e22a794899c91b7d8c8e12eaacac8df249faafe
|
||||
F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291
|
||||
F test/index.test df7c00c6edd9504ab71c83a9514f1c5ca0fa54d8
|
||||
F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/indexedby.test be501e381b82b2f8ab406309ba7aac46e221f4ad
|
||||
@@ -560,6 +566,7 @@ F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
|
||||
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
|
||||
F test/malloc_common.tcl 660b82ab528521cc4a48ff6df05ca3b6a00d47c5
|
||||
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
|
||||
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
|
||||
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
|
||||
F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2
|
||||
F test/memsubsys1.test 679db68394a5692791737b150852173b3e2fea10
|
||||
@@ -584,8 +591,9 @@ F test/notify2.test 195a467e021f74197be2c4fb02d6dee644b8d8db
|
||||
F test/notify3.test d60923e186e0900f4812a845fcdfd8eea096e33a
|
||||
F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
|
||||
F test/null.test a8b09b8ed87852742343b33441a9240022108993
|
||||
F test/omitunique.test bbb2ec4345d9125d9ee21cd9488d97a163020d5f
|
||||
F test/openv2.test af02ed0a9cbc0d2a61b8f35171d4d117e588e4ec
|
||||
F test/oserror.test 5775264a41039856d211168713d916949227fedd
|
||||
F test/oserror.test d1f085bdbac20456fccdf5877f52016453654fc3
|
||||
F test/pager1.test d8672fd0af5f4f9b99b06283d00f01547809bebe
|
||||
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
@@ -600,7 +608,7 @@ F test/permutations.test 5b2a4cb756ffb2407cb4743163668d1d769febb6
|
||||
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
|
||||
@@ -888,12 +896,12 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
|
||||
F tool/lemon.c dfd81a51b6e27e469ba21d01a75ddf092d429027
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
|
||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c.tcl cf44512a48112b1ba09590548660a5a6877afdb3
|
||||
F tool/mksqlite3h.tcl d76c226a5e8e1f3b5f6593bcabe5e98b3b1ec9ff
|
||||
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
|
||||
F tool/omittest.tcl 71c6f21afa2df91dd299ed317d5751fb628795fe
|
||||
F tool/omittest.tcl 4f4cc66bb7ca6a5b8f61ee37b6333f60fb8a746a
|
||||
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
|
||||
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
|
||||
F tool/shell1.test f608a009b04c490fd360c5ded458a6f98b4e7ec4
|
||||
@@ -913,7 +921,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 526545c49f64d9063d1b888cfc14ece62fa3c13c
|
||||
R cab2f9d8485568249e1bae732085445e
|
||||
U dan
|
||||
Z 0451d1109f54d52c16342adf23f8ece9
|
||||
P 6614cfcb9c41da71ddec3c44a3de0d4d849e1cdd 54bacb95dd6e2d6ac4971391a40484ccb9126d29
|
||||
R e54868c8ee7f58a0691b9e0694987cf6
|
||||
U drh
|
||||
Z 8149dc4ff84780eb7c2d29113d1dc5ec
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFNg1GboxKgR168RlERAptpAJ4+cfNBHl8w0y578KOanLZsuj14mgCffUXp
|
||||
W65/Ci2dAe+flL3fcPt3X+4=
|
||||
=uYuP
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@@ -1 +1 @@
|
||||
6614cfcb9c41da71ddec3c44a3de0d4d849e1cdd
|
||||
94fd5bb6da5ef4d850c2ed4ad38afabc5569dae6
|
@@ -4901,11 +4901,9 @@ static int allocateBtreePage(
|
||||
u32 i;
|
||||
int dist;
|
||||
closest = 0;
|
||||
dist = get4byte(&aData[8]) - nearby;
|
||||
if( dist<0 ) dist = -dist;
|
||||
dist = sqlite3AbsInt32(get4byte(&aData[8]) - nearby);
|
||||
for(i=1; i<k; i++){
|
||||
int d2 = get4byte(&aData[8+i*4]) - nearby;
|
||||
if( d2<0 ) d2 = -d2;
|
||||
int d2 = sqlite3AbsInt32(get4byte(&aData[8+i*4]) - nearby);
|
||||
if( d2<dist ){
|
||||
closest = i;
|
||||
dist = d2;
|
||||
@@ -6179,9 +6177,7 @@ static int balance_nonroot(
|
||||
}
|
||||
}
|
||||
if( minI>i ){
|
||||
int t;
|
||||
MemPage *pT;
|
||||
t = apNew[i]->pgno;
|
||||
pT = apNew[i];
|
||||
apNew[i] = apNew[minI];
|
||||
apNew[minI] = pT;
|
||||
|
@@ -302,6 +302,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION
|
||||
"OMIT_TRUNCATE_OPTIMIZATION",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
"OMIT_UNIQUE_ENFORCEMENT",
|
||||
#endif
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
"OMIT_UTF16",
|
||||
#endif
|
||||
|
13
src/expr.c
13
src/expr.c
@@ -389,6 +389,7 @@ Expr *sqlite3ExprAlloc(
|
||||
if( op!=TK_INTEGER || pToken->z==0
|
||||
|| sqlite3GetInt32(pToken->z, &iValue)==0 ){
|
||||
nExtra = pToken->n+1;
|
||||
assert( iValue>=0 );
|
||||
}
|
||||
}
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(Expr)+nExtra);
|
||||
@@ -614,6 +615,8 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||
*/
|
||||
void sqlite3ExprDelete(sqlite3 *db, Expr *p){
|
||||
if( p==0 ) return;
|
||||
/* Sanity check: Assert that the IntValue is non-negative if it exists */
|
||||
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
|
||||
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
|
||||
sqlite3ExprDelete(db, p->pLeft);
|
||||
sqlite3ExprDelete(db, p->pRight);
|
||||
@@ -1223,13 +1226,6 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
if( rc ){
|
||||
assert( ExprHasAnyProperty(p, EP_Reduced|EP_TokenOnly)
|
||||
|| (p->flags2 & EP2_MallocedToken)==0 );
|
||||
p->op = TK_INTEGER;
|
||||
p->flags |= EP_IntValue;
|
||||
p->u.iValue = *pValue;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1954,6 +1950,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( pExpr->flags & EP_IntValue ){
|
||||
int i = pExpr->u.iValue;
|
||||
assert( i>=0 );
|
||||
if( negFlag ) i = -i;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
|
||||
}else{
|
||||
@@ -1964,7 +1961,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
|
||||
c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
|
||||
if( c==0 || (c==2 && negFlag) ){
|
||||
char *zV;
|
||||
if( negFlag ){ value = -value; }
|
||||
if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; }
|
||||
zV = dup8bytes(v, (char*)&value);
|
||||
sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
|
||||
}else{
|
||||
|
@@ -687,7 +687,6 @@ void sqlite3FkCheck(
|
||||
int regNew /* New row data is stored here */
|
||||
){
|
||||
sqlite3 *db = pParse->db; /* Database handle */
|
||||
Vdbe *v; /* VM to write code to */
|
||||
FKey *pFKey; /* Used to iterate through FKs */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
const char *zDb; /* Name of database containing pTab */
|
||||
@@ -699,7 +698,6 @@ void sqlite3FkCheck(
|
||||
/* If foreign-keys are disabled, this function is a no-op. */
|
||||
if( (db->flags&SQLITE_ForeignKeys)==0 ) return;
|
||||
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
zDb = db->aDb[iDb].zName;
|
||||
|
||||
|
@@ -1239,13 +1239,8 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( type==SQLITE_INTEGER ){
|
||||
i64 v = sqlite3_value_int64(argv[0]);
|
||||
p->rSum += v;
|
||||
if( (p->approx|p->overflow)==0 ){
|
||||
i64 iNewSum = p->iSum + v;
|
||||
int s1 = (int)(p->iSum >> (sizeof(i64)*8-1));
|
||||
int s2 = (int)(v >> (sizeof(i64)*8-1));
|
||||
int s3 = (int)(iNewSum >> (sizeof(i64)*8-1));
|
||||
p->overflow = ((s1&s2&~s3) | (~s1&~s2&s3))?1:0;
|
||||
p->iSum = iNewSum;
|
||||
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
|
||||
p->overflow = 1;
|
||||
}
|
||||
}else{
|
||||
p->rSum += sqlite3_value_double(argv[0]);
|
||||
|
13
src/insert.c
13
src/insert.c
@@ -465,7 +465,6 @@ void sqlite3Insert(
|
||||
int regIns; /* Block of regs holding rowid+data being inserted */
|
||||
int regRowid; /* registers holding insert rowid */
|
||||
int regData; /* register holding first column to insert */
|
||||
int regRecord; /* Holds the assemblied row record */
|
||||
int regEof = 0; /* Register recording end of SELECT data */
|
||||
int *aRegIdx = 0; /* One register allocated to each index */
|
||||
|
||||
@@ -794,7 +793,6 @@ void sqlite3Insert(
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
** the content of the new row, and the assemblied row record.
|
||||
*/
|
||||
regRecord = ++pParse->nMem;
|
||||
regRowid = regIns = pParse->nMem+1;
|
||||
pParse->nMem += pTab->nCol + 1;
|
||||
if( IsVirtual(pTab) ){
|
||||
@@ -1188,7 +1186,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
case OE_Rollback:
|
||||
case OE_Fail: {
|
||||
char *zMsg;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_HaltIfNull,
|
||||
sqlite3VdbeAddOp3(v, OP_HaltIfNull,
|
||||
SQLITE_CONSTRAINT, onError, regData+i);
|
||||
zMsg = sqlite3MPrintf(pParse->db, "%s.%s may not be NULL",
|
||||
pTab->zName, pTab->aCol[i].zName);
|
||||
@@ -1320,8 +1318,9 @@ void sqlite3GenerateConstraintChecks(
|
||||
*/
|
||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
||||
int regIdx;
|
||||
#ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
int regR;
|
||||
|
||||
#endif
|
||||
if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
|
||||
|
||||
/* Create a key for accessing the index entry */
|
||||
@@ -1339,6 +1338,11 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), 0);
|
||||
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1);
|
||||
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
|
||||
continue; /* Treat pIdx as if it is not a UNIQUE index */
|
||||
#else
|
||||
|
||||
/* Find out what action to take in case there is an indexing conflict */
|
||||
onError = pIdx->onError;
|
||||
if( onError==OE_None ){
|
||||
@@ -1412,6 +1416,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3ReleaseTempReg(pParse, regR);
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pbMayReplace ){
|
||||
|
@@ -375,6 +375,13 @@ int sqlite3_config(int op, ...){
|
||||
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
|
||||
sqlite3GlobalConfig.mnReq = va_arg(ap, int);
|
||||
|
||||
if( sqlite3GlobalConfig.mnReq<1 ){
|
||||
sqlite3GlobalConfig.mnReq = 1;
|
||||
}else if( sqlite3GlobalConfig.mnReq>(1<<12) ){
|
||||
/* cap min request size at 2^12 */
|
||||
sqlite3GlobalConfig.mnReq = (1<<12);
|
||||
}
|
||||
|
||||
if( sqlite3GlobalConfig.pHeap==0 ){
|
||||
/* If the heap pointer is NULL, then restore the malloc implementation
|
||||
** back to NULL pointers too. This will cause the malloc to go
|
||||
|
@@ -442,7 +442,7 @@ static int memsys5Roundup(int n){
|
||||
*/
|
||||
static int memsys5Log(int iValue){
|
||||
int iLog;
|
||||
for(iLog=0; (1<<iLog)<iValue; iLog++);
|
||||
for(iLog=0; (iLog<((sizeof(int)*8)-1)) && (1<<iLog)<iValue; iLog++);
|
||||
return iLog;
|
||||
}
|
||||
|
||||
@@ -473,6 +473,7 @@ static int memsys5Init(void *NotUsed){
|
||||
zByte = (u8*)sqlite3GlobalConfig.pHeap;
|
||||
assert( zByte!=0 ); /* sqlite3_config() does not allow otherwise */
|
||||
|
||||
/* boundaries on sqlite3GlobalConfig.mnReq are enforced in sqlite3_config() */
|
||||
nMinLog = memsys5Log(sqlite3GlobalConfig.mnReq);
|
||||
mem5.szAtom = (1<<nMinLog);
|
||||
while( (int)sizeof(Mem5Link)>mem5.szAtom ){
|
||||
|
113
src/mutex_os2.c
113
src/mutex_os2.c
@@ -31,11 +31,16 @@
|
||||
struct sqlite3_mutex {
|
||||
HMTX mutex; /* Mutex controlling the lock */
|
||||
int id; /* Mutex type */
|
||||
int nRef; /* Number of references */
|
||||
TID owner; /* Thread holding this mutex */
|
||||
#ifdef SQLITE_DEBUG
|
||||
int trace; /* True to trace changes */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define OS2_MUTEX_INITIALIZER 0,0,0,0
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define SQLITE3_MUTEX_INITIALIZER { 0, 0, 0 }
|
||||
#else
|
||||
#define SQLITE3_MUTEX_INITIALIZER { 0, 0 }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
@@ -51,11 +56,14 @@ static int os2MutexEnd(void){ return SQLITE_OK; }
|
||||
** to sqlite3_mutex_alloc() is one of these integer constants:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST 0
|
||||
** <li> SQLITE_MUTEX_RECURSIVE 1
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER 2
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM 3
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG 4
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
@@ -69,7 +77,7 @@ static int os2MutexEnd(void){ return SQLITE_OK; }
|
||||
** might return such a mutex in response to SQLITE_MUTEX_FAST.
|
||||
**
|
||||
** The other allowed parameters to sqlite3_mutex_alloc() each return
|
||||
** a pointer to a static preexisting mutex. Three static mutexes are
|
||||
** a pointer to a static preexisting mutex. Six static mutexes are
|
||||
** used by the current version of SQLite. Future versions of SQLite
|
||||
** may add additional static mutexes. Static mutexes are for internal
|
||||
** use by SQLite only. Applications that use SQLite mutexes should
|
||||
@@ -99,13 +107,13 @@ static sqlite3_mutex *os2MutexAlloc(int iType){
|
||||
}
|
||||
default: {
|
||||
static volatile int isInit = 0;
|
||||
static sqlite3_mutex staticMutexes[] = {
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
{ OS2_MUTEX_INITIALIZER, },
|
||||
static sqlite3_mutex staticMutexes[6] = {
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
};
|
||||
if ( !isInit ){
|
||||
APIRET rc;
|
||||
@@ -151,9 +159,14 @@ static sqlite3_mutex *os2MutexAlloc(int iType){
|
||||
** SQLite is careful to deallocate every mutex that it allocates.
|
||||
*/
|
||||
static void os2MutexFree(sqlite3_mutex *p){
|
||||
if( p==0 ) return;
|
||||
assert( p->nRef==0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
TID tid;
|
||||
PID pid;
|
||||
ULONG ulCount;
|
||||
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
|
||||
assert( ulCount==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
DosCloseMutexSem( p->mutex );
|
||||
sqlite3_free( p );
|
||||
}
|
||||
@@ -168,26 +181,29 @@ static int os2MutexHeld(sqlite3_mutex *p){
|
||||
PID pid;
|
||||
ULONG ulCount;
|
||||
PTIB ptib;
|
||||
if( p!=0 ) {
|
||||
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
|
||||
} else {
|
||||
if( ulCount==0 || ( ulCount>1 && p->id!=SQLITE_MUTEX_RECURSIVE ) )
|
||||
return 0;
|
||||
DosGetInfoBlocks(&ptib, NULL);
|
||||
tid = ptib->tib_ptib2->tib2_ultid;
|
||||
}
|
||||
return p==0 || (p->nRef!=0 && p->owner==tid);
|
||||
return tid==ptib->tib_ptib2->tib2_ultid;
|
||||
}
|
||||
static int os2MutexNotheld(sqlite3_mutex *p){
|
||||
TID tid;
|
||||
PID pid;
|
||||
ULONG ulCount;
|
||||
PTIB ptib;
|
||||
if( p!= 0 ) {
|
||||
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
|
||||
} else {
|
||||
if( ulCount==0 )
|
||||
return 1;
|
||||
DosGetInfoBlocks(&ptib, NULL);
|
||||
tid = ptib->tib_ptib2->tib2_ultid;
|
||||
return tid!=ptib->tib_ptib2->tib2_ultid;
|
||||
}
|
||||
return p==0 || p->nRef==0 || p->owner!=tid;
|
||||
static void os2MutexTrace(sqlite3_mutex *p, char *pAction){
|
||||
TID tid;
|
||||
PID pid;
|
||||
ULONG ulCount;
|
||||
DosQueryMutexSem(p->mutex, &pid, &tid, &ulCount);
|
||||
printf("%s mutex %p (%d) with nRef=%ld\n", pAction, (void*)p, p->trace, ulCount);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -203,32 +219,21 @@ static int os2MutexNotheld(sqlite3_mutex *p){
|
||||
** more than once, the behavior is undefined.
|
||||
*/
|
||||
static void os2MutexEnter(sqlite3_mutex *p){
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
if( p==0 ) return;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
|
||||
DosRequestMutexSem(p->mutex, SEM_INDEFINITE_WAIT);
|
||||
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ) os2MutexTrace(p, "enter");
|
||||
#endif
|
||||
}
|
||||
static int os2MutexTry(sqlite3_mutex *p){
|
||||
int rc;
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
if( p==0 ) return SQLITE_OK;
|
||||
int rc = SQLITE_BUSY;
|
||||
assert( p->id==SQLITE_MUTEX_RECURSIVE || os2MutexNotheld(p) );
|
||||
if( DosRequestMutexSem(p->mutex, SEM_IMMEDIATE_RETURN) == NO_ERROR ) {
|
||||
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
rc = SQLITE_OK;
|
||||
} else {
|
||||
rc = SQLITE_BUSY;
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ) os2MutexTrace(p, "try");
|
||||
#endif
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -239,19 +244,14 @@ static int os2MutexTry(sqlite3_mutex *p){
|
||||
** is not currently allocated. SQLite will never do either.
|
||||
*/
|
||||
static void os2MutexLeave(sqlite3_mutex *p){
|
||||
TID tid;
|
||||
PID holder1;
|
||||
ULONG holder2;
|
||||
if( p==0 ) return;
|
||||
assert( p->nRef>0 );
|
||||
DosQueryMutexSem(p->mutex, &holder1, &tid, &holder2);
|
||||
assert( p->owner==tid );
|
||||
p->nRef--;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
assert( os2MutexHeld(p) );
|
||||
DosReleaseMutexSem(p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ) os2MutexTrace(p, "leave");
|
||||
#endif
|
||||
}
|
||||
|
||||
sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
static const sqlite3_mutex_methods sMutex = {
|
||||
os2MutexInit,
|
||||
os2MutexEnd,
|
||||
@@ -263,6 +263,9 @@ sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
|
||||
#ifdef SQLITE_DEBUG
|
||||
os2MutexHeld,
|
||||
os2MutexNotheld
|
||||
#else
|
||||
0,
|
||||
0
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@@ -280,7 +280,7 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( rc==SQLITE_OK && p->trace ){
|
||||
printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
|
215
src/os_os2.c
215
src/os_os2.c
@@ -647,18 +647,22 @@ char *convertCpPathToUtf8( const char *in ){
|
||||
*/
|
||||
static const sqlite3_io_methods os2IoMethod = {
|
||||
1, /* iVersion */
|
||||
os2Close,
|
||||
os2Read,
|
||||
os2Write,
|
||||
os2Truncate,
|
||||
os2Sync,
|
||||
os2FileSize,
|
||||
os2Lock,
|
||||
os2Unlock,
|
||||
os2CheckReservedLock,
|
||||
os2FileControl,
|
||||
os2SectorSize,
|
||||
os2DeviceCharacteristics
|
||||
os2Close, /* xClose */
|
||||
os2Read, /* xRead */
|
||||
os2Write, /* xWrite */
|
||||
os2Truncate, /* xTruncate */
|
||||
os2Sync, /* xSync */
|
||||
os2FileSize, /* xFileSize */
|
||||
os2Lock, /* xLock */
|
||||
os2Unlock, /* xUnlock */
|
||||
os2CheckReservedLock, /* xCheckReservedLock */
|
||||
os2FileControl, /* xFileControl */
|
||||
os2SectorSize, /* xSectorSize */
|
||||
os2DeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
0, /* xShmMap */
|
||||
0, /* xShmLock */
|
||||
0, /* xShmBarrier */
|
||||
0 /* xShmUnmap */
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
@@ -750,100 +754,137 @@ static int os2FullPathname(
|
||||
*/
|
||||
static int os2Open(
|
||||
sqlite3_vfs *pVfs, /* Not used */
|
||||
const char *zName, /* Name of the file */
|
||||
const char *zName, /* Name of the file (UTF-8) */
|
||||
sqlite3_file *id, /* Write the SQLite file handle here */
|
||||
int flags, /* Open mode flags */
|
||||
int *pOutFlags /* Status return flags */
|
||||
){
|
||||
HFILE h;
|
||||
ULONG ulFileAttribute = FILE_NORMAL;
|
||||
ULONG ulOpenFlags = 0;
|
||||
ULONG ulOpenMode = 0;
|
||||
ULONG ulAction = 0;
|
||||
ULONG rc;
|
||||
os2File *pFile = (os2File*)id;
|
||||
APIRET rc = NO_ERROR;
|
||||
ULONG ulAction;
|
||||
const char *zUtf8Name = zName;
|
||||
char *zNameCp;
|
||||
char zTmpname[CCHMAXPATH+1]; /* Buffer to hold name of temp file */
|
||||
char zTmpname[CCHMAXPATH];
|
||||
|
||||
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
|
||||
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
|
||||
int isCreate = (flags & SQLITE_OPEN_CREATE);
|
||||
int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
|
||||
#ifndef NDEBUG
|
||||
int isReadonly = (flags & SQLITE_OPEN_READONLY);
|
||||
int eType = (flags & 0xFFFFFF00);
|
||||
int isOpenJournal = (isCreate && (
|
||||
eType==SQLITE_OPEN_MASTER_JOURNAL
|
||||
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|
||||
|| eType==SQLITE_OPEN_WAL
|
||||
));
|
||||
#endif
|
||||
|
||||
UNUSED_PARAMETER(pVfs);
|
||||
assert( id!=0 );
|
||||
|
||||
/* Check the following statements are true:
|
||||
**
|
||||
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
|
||||
** (b) if CREATE is set, then READWRITE must also be set, and
|
||||
** (c) if EXCLUSIVE is set, then CREATE must also be set.
|
||||
** (d) if DELETEONCLOSE is set, then CREATE must also be set.
|
||||
*/
|
||||
assert((isReadonly==0 || isReadWrite==0) && (isReadWrite || isReadonly));
|
||||
assert(isCreate==0 || isReadWrite);
|
||||
assert(isExclusive==0 || isCreate);
|
||||
assert(isDelete==0 || isCreate);
|
||||
|
||||
/* The main DB, main journal, WAL file and master journal are never
|
||||
** automatically deleted. Nor are they ever temporary files. */
|
||||
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_DB );
|
||||
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MAIN_JOURNAL );
|
||||
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_MASTER_JOURNAL );
|
||||
assert( (!isDelete && zName) || eType!=SQLITE_OPEN_WAL );
|
||||
|
||||
/* Assert that the upper layer has set one of the "file-type" flags. */
|
||||
assert( eType==SQLITE_OPEN_MAIN_DB || eType==SQLITE_OPEN_TEMP_DB
|
||||
|| eType==SQLITE_OPEN_MAIN_JOURNAL || eType==SQLITE_OPEN_TEMP_JOURNAL
|
||||
|| eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL
|
||||
|| eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL
|
||||
);
|
||||
|
||||
memset( pFile, 0, sizeof(*pFile) );
|
||||
pFile->pMethod = &os2IoMethod;
|
||||
|
||||
/* If the second argument to this function is NULL, generate a
|
||||
** temporary file name to use
|
||||
*/
|
||||
if( !zName ){
|
||||
int rc = getTempname(CCHMAXPATH+1, zTmpname);
|
||||
if( !zUtf8Name ){
|
||||
assert(isDelete && !isOpenJournal);
|
||||
rc = getTempname(CCHMAXPATH, zTmpname);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
zName = zTmpname;
|
||||
zUtf8Name = zTmpname;
|
||||
}
|
||||
|
||||
|
||||
memset( pFile, 0, sizeof(*pFile) );
|
||||
|
||||
OSTRACE(( "OPEN want %d\n", flags ));
|
||||
|
||||
if( flags & SQLITE_OPEN_READWRITE ){
|
||||
if( isReadWrite ){
|
||||
ulOpenMode |= OPEN_ACCESS_READWRITE;
|
||||
OSTRACE(( "OPEN read/write\n" ));
|
||||
}else{
|
||||
ulOpenMode |= OPEN_ACCESS_READONLY;
|
||||
OSTRACE(( "OPEN read only\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_CREATE ){
|
||||
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
|
||||
OSTRACE(( "OPEN open new/create\n" ));
|
||||
}else{
|
||||
ulOpenFlags |= OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW;
|
||||
OSTRACE(( "OPEN open existing\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_MAIN_DB ){
|
||||
ulOpenMode |= OPEN_SHARE_DENYNONE;
|
||||
OSTRACE(( "OPEN share read/write\n" ));
|
||||
}else{
|
||||
ulOpenMode |= OPEN_SHARE_DENYWRITE;
|
||||
OSTRACE(( "OPEN share read only\n" ));
|
||||
}
|
||||
|
||||
if( flags & SQLITE_OPEN_DELETEONCLOSE ){
|
||||
char pathUtf8[CCHMAXPATH];
|
||||
#ifdef NDEBUG /* when debugging we want to make sure it is deleted */
|
||||
ulFileAttribute = FILE_HIDDEN;
|
||||
#endif
|
||||
os2FullPathname( pVfs, zName, CCHMAXPATH, pathUtf8 );
|
||||
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
|
||||
OSTRACE(( "OPEN hidden/delete on close file attributes\n" ));
|
||||
}else{
|
||||
pFile->pathToDel = NULL;
|
||||
OSTRACE(( "OPEN normal file attribute\n" ));
|
||||
}
|
||||
|
||||
/* always open in random access mode for possibly better speed */
|
||||
/* Open in random access mode for possibly better speed. Allow full
|
||||
** sharing because file locks will provide exclusive access when needed.
|
||||
*/
|
||||
ulOpenMode |= OPEN_FLAGS_RANDOM;
|
||||
ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR;
|
||||
ulOpenMode |= OPEN_FLAGS_NOINHERIT;
|
||||
ulOpenMode |= OPEN_SHARE_DENYNONE;
|
||||
|
||||
zNameCp = convertUtf8PathToCp( zName );
|
||||
/* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is
|
||||
** created. SQLite doesn't use it to indicate "exclusive access"
|
||||
** as it is usually understood.
|
||||
*/
|
||||
if( isExclusive ){
|
||||
/* Creates a new file, only if it does not already exist. */
|
||||
/* If the file exists, it fails. */
|
||||
ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
|
||||
}else if( isCreate ){
|
||||
/* Open existing file, or create if it doesn't exist */
|
||||
ulOpenFlags |= OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
|
||||
}else{
|
||||
/* Opens a file, only if it exists. */
|
||||
ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
|
||||
}
|
||||
|
||||
/* For DELETEONCLOSE, save a pointer to the converted filename */
|
||||
if( isDelete ){
|
||||
char pathUtf8[CCHMAXPATH];
|
||||
os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 );
|
||||
pFile->pathToDel = convertUtf8PathToCp( pathUtf8 );
|
||||
}
|
||||
|
||||
zNameCp = convertUtf8PathToCp( zUtf8Name );
|
||||
rc = DosOpen( (PSZ)zNameCp,
|
||||
&h,
|
||||
&ulAction,
|
||||
0L,
|
||||
ulFileAttribute,
|
||||
FILE_NORMAL,
|
||||
ulOpenFlags,
|
||||
ulOpenMode,
|
||||
(PEAOP2)NULL );
|
||||
free( zNameCp );
|
||||
|
||||
if( rc != NO_ERROR ){
|
||||
OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulAttr=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
|
||||
rc, zName, ulAction, ulFileAttribute, ulOpenFlags, ulOpenMode ));
|
||||
OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n",
|
||||
rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode ));
|
||||
if( pFile->pathToDel )
|
||||
free( pFile->pathToDel );
|
||||
pFile->pathToDel = NULL;
|
||||
if( flags & SQLITE_OPEN_READWRITE ){
|
||||
OSTRACE(( "OPEN %d Invalid handle\n",
|
||||
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE) ));
|
||||
|
||||
if( isReadWrite ){
|
||||
return os2Open( pVfs, zName, id,
|
||||
((flags | SQLITE_OPEN_READONLY) & ~SQLITE_OPEN_READWRITE),
|
||||
((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)),
|
||||
pOutFlags );
|
||||
}else{
|
||||
return SQLITE_CANTOPEN;
|
||||
@@ -851,10 +892,9 @@ static int os2Open(
|
||||
}
|
||||
|
||||
if( pOutFlags ){
|
||||
*pOutFlags = flags & SQLITE_OPEN_READWRITE ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
|
||||
*pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY;
|
||||
}
|
||||
|
||||
pFile->pMethod = &os2IoMethod;
|
||||
pFile->h = h;
|
||||
OpenCounter(+1);
|
||||
OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags ));
|
||||
@@ -869,13 +909,16 @@ static int os2Delete(
|
||||
const char *zFilename, /* Name of file to delete */
|
||||
int syncDir /* Not used on os2 */
|
||||
){
|
||||
APIRET rc = NO_ERROR;
|
||||
char *zFilenameCp = convertUtf8PathToCp( zFilename );
|
||||
APIRET rc;
|
||||
char *zFilenameCp;
|
||||
SimulateIOError( return SQLITE_IOERR_DELETE );
|
||||
zFilenameCp = convertUtf8PathToCp( zFilename );
|
||||
rc = DosDelete( (PSZ)zFilenameCp );
|
||||
free( zFilenameCp );
|
||||
OSTRACE(( "DELETE \"%s\"\n", zFilename ));
|
||||
return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_DELETE;
|
||||
return (rc == NO_ERROR ||
|
||||
rc == ERROR_FILE_NOT_FOUND ||
|
||||
rc == ERROR_PATH_NOT_FOUND ) ? SQLITE_OK : SQLITE_IOERR_DELETE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -940,7 +983,7 @@ static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){
|
||||
static void os2DlError(sqlite3_vfs *pVfs, int nBuf, char *zBufOut){
|
||||
/* no-op */
|
||||
}
|
||||
static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
|
||||
static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){
|
||||
PFN pfn;
|
||||
APIRET rc;
|
||||
rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn);
|
||||
@@ -952,7 +995,7 @@ static void *os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol){
|
||||
strncat(_zSymbol, zSymbol, 255);
|
||||
rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn);
|
||||
}
|
||||
return rc != NO_ERROR ? 0 : (void*)pfn;
|
||||
return rc != NO_ERROR ? 0 : (void(*)(void))pfn;
|
||||
}
|
||||
static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
DosFreeModule((HMODULE)pHandle);
|
||||
@@ -1056,10 +1099,11 @@ int sqlite3_current_time = 0;
|
||||
int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
|
||||
double now;
|
||||
SHORT minute; /* needs to be able to cope with negative timezone offset */
|
||||
USHORT second, hour,
|
||||
USHORT hundredths, second, hour,
|
||||
day, month, year;
|
||||
DATETIME dt;
|
||||
DosGetDateTime( &dt );
|
||||
hundredths = (USHORT)dt.hundredths;
|
||||
second = (USHORT)dt.seconds;
|
||||
minute = (SHORT)dt.minutes + dt.timezone;
|
||||
hour = (USHORT)dt.hours;
|
||||
@@ -1079,6 +1123,7 @@ int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
|
||||
now += (hour + 12.0)/24.0;
|
||||
now += minute/1440.0;
|
||||
now += second/86400.0;
|
||||
now += hundredths/8640000.0;
|
||||
*prNow = now;
|
||||
#ifdef SQLITE_TEST
|
||||
if( sqlite3_current_time ){
|
||||
@@ -1088,6 +1133,22 @@ int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the current time (in Universal Coordinated Time). Write into *piNow
|
||||
** the current time and date as a Julian Day number times 86_400_000. In
|
||||
** other words, write into *piNow the number of milliseconds since the Julian
|
||||
** epoch of noon in Greenwich on November 24, 4714 B.C according to the
|
||||
** proleptic Gregorian calendar.
|
||||
**
|
||||
** On success, return 0. Return 1 if the time and date cannot be found.
|
||||
*/
|
||||
static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){
|
||||
double now;
|
||||
os2CurrentTime(pVfs, &now);
|
||||
*piNow = now * 86400000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
return 0;
|
||||
}
|
||||
@@ -1097,7 +1158,7 @@ static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
*/
|
||||
int sqlite3_os_init(void){
|
||||
static sqlite3_vfs os2Vfs = {
|
||||
1, /* iVersion */
|
||||
3, /* iVersion */
|
||||
sizeof(os2File), /* szOsFile */
|
||||
CCHMAXPATH, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@@ -1116,6 +1177,10 @@ int sqlite3_os_init(void){
|
||||
os2Sleep, /* xSleep */
|
||||
os2CurrentTime, /* xCurrentTime */
|
||||
os2GetLastError, /* xGetLastError */
|
||||
os2CurrentTimeInt64 /* xCurrentTimeInt64 */
|
||||
0, /* xSetSystemCall */
|
||||
0, /* xGetSystemCall */
|
||||
0, /* xNextSystemCall */
|
||||
};
|
||||
sqlite3_vfs_register(&os2Vfs, 1);
|
||||
initUconvObjects();
|
||||
|
587
src/os_unix.c
587
src/os_unix.c
File diff suppressed because it is too large
Load Diff
@@ -2746,7 +2746,7 @@ static int winGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){
|
||||
*/
|
||||
int sqlite3_os_init(void){
|
||||
static sqlite3_vfs winVfs = {
|
||||
2, /* iVersion */
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
MAX_PATH, /* mxPathname */
|
||||
0, /* pNext */
|
||||
@@ -2765,6 +2765,9 @@ int sqlite3_os_init(void){
|
||||
winCurrentTime, /* xCurrentTime */
|
||||
winGetLastError, /* xGetLastError */
|
||||
winCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
0, /* xSetSystemCall */
|
||||
0, /* xGetSystemCall */
|
||||
0, /* xNextSystemCall */
|
||||
};
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
@@ -384,8 +384,7 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeChangeP1(v, addr+1, iDb);
|
||||
sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
|
||||
}else{
|
||||
int size = sqlite3Atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
|
||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
|
||||
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
|
||||
@@ -694,8 +693,7 @@ void sqlite3Pragma(
|
||||
if( !zRight ){
|
||||
returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size);
|
||||
}else{
|
||||
int size = sqlite3Atoi(zRight);
|
||||
if( size<0 ) size = -size;
|
||||
int size = sqlite3AbsInt32(sqlite3Atoi(zRight));
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
|
@@ -141,7 +141,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
int meta[5];
|
||||
InitData initData;
|
||||
char const *zMasterSchema;
|
||||
char const *zMasterName = SCHEMA_TABLE(iDb);
|
||||
char const *zMasterName;
|
||||
int openedTransaction = 0;
|
||||
|
||||
/*
|
||||
@@ -278,9 +278,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
||||
pDb->pSchema->enc = ENC(db);
|
||||
|
||||
if( pDb->pSchema->cache_size==0 ){
|
||||
size = meta[BTREE_DEFAULT_CACHE_SIZE-1];
|
||||
size = sqlite3AbsInt32(meta[BTREE_DEFAULT_CACHE_SIZE-1]);
|
||||
if( size==0 ){ size = SQLITE_DEFAULT_CACHE_SIZE; }
|
||||
if( size<0 ) size = -size;
|
||||
pDb->pSchema->cache_size = size;
|
||||
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
|
||||
}
|
||||
|
@@ -400,7 +400,11 @@ void sqlite3VXPrintf(
|
||||
v = va_arg(ap,int);
|
||||
}
|
||||
if( v<0 ){
|
||||
if( v==SMALLEST_INT64 ){
|
||||
longvalue = ((u64)1)<<63;
|
||||
}else{
|
||||
longvalue = -v;
|
||||
}
|
||||
prefix = '-';
|
||||
}else{
|
||||
longvalue = v;
|
||||
|
105
src/shell.c
105
src/shell.c
@@ -419,6 +419,7 @@ struct callback_data {
|
||||
** .explain ON */
|
||||
char outfile[FILENAME_MAX]; /* Filename for *out */
|
||||
const char *zDbFilename; /* name of the database file */
|
||||
const char *zVfs; /* Name of VFS to use */
|
||||
sqlite3_stmt *pStmt; /* Current statement if any. */
|
||||
FILE *pLog; /* Write log output here */
|
||||
};
|
||||
@@ -2172,29 +2173,45 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
}else
|
||||
|
||||
if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
|
||||
static const struct {
|
||||
const char *zCtrlName; /* Name of a test-control option */
|
||||
int ctrlCode; /* Integer code for that option */
|
||||
} aCtrl[] = {
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE },
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE },
|
||||
{ "prng_reset", SQLITE_TESTCTRL_PRNG_RESET },
|
||||
{ "bitvec_test", SQLITE_TESTCTRL_BITVEC_TEST },
|
||||
{ "fault_install", SQLITE_TESTCTRL_FAULT_INSTALL },
|
||||
{ "benign_malloc_hooks", SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS },
|
||||
{ "pending_byte", SQLITE_TESTCTRL_PENDING_BYTE },
|
||||
{ "assert", SQLITE_TESTCTRL_ASSERT },
|
||||
{ "always", SQLITE_TESTCTRL_ALWAYS },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE },
|
||||
{ "optimizations", SQLITE_TESTCTRL_OPTIMIZATIONS },
|
||||
{ "iskeyword", SQLITE_TESTCTRL_ISKEYWORD },
|
||||
{ "pghdrsz", SQLITE_TESTCTRL_PGHDRSZ },
|
||||
{ "scratchmalloc", SQLITE_TESTCTRL_SCRATCHMALLOC },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int rc = 0;
|
||||
int i, n;
|
||||
open_db(p);
|
||||
|
||||
/* convert testctrl text option to value. allow only the first
|
||||
** three characters of the option to be used or the numerical
|
||||
** value. */
|
||||
if( strncmp( azArg[1], "prng_save", 6 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_SAVE;
|
||||
else if( strncmp( azArg[1], "prng_restore", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESTORE;
|
||||
else if( strncmp( azArg[1], "prng_reset", 10 )==0 ) testctrl = SQLITE_TESTCTRL_PRNG_RESET;
|
||||
else if( strncmp( azArg[1], "bitvec_test", 6 )==3 ) testctrl = SQLITE_TESTCTRL_BITVEC_TEST;
|
||||
else if( strncmp( azArg[1], "fault_install", 6 )==3 ) testctrl = SQLITE_TESTCTRL_FAULT_INSTALL;
|
||||
else if( strncmp( azArg[1], "benign_malloc_hooks", 3 )==0 ) testctrl = SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS;
|
||||
else if( strncmp( azArg[1], "pending_byte", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PENDING_BYTE;
|
||||
else if( strncmp( azArg[1], "assert", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ASSERT;
|
||||
else if( strncmp( azArg[1], "always", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ALWAYS;
|
||||
else if( strncmp( azArg[1], "reserve", 3 )==0 ) testctrl = SQLITE_TESTCTRL_RESERVE;
|
||||
else if( strncmp( azArg[1], "optimizations", 3 )==0 ) testctrl = SQLITE_TESTCTRL_OPTIMIZATIONS;
|
||||
else if( strncmp( azArg[1], "iskeyword", 3 )==0 ) testctrl = SQLITE_TESTCTRL_ISKEYWORD;
|
||||
else if( strncmp( azArg[1], "pghdrsz", 3 )==0 ) testctrl = SQLITE_TESTCTRL_PGHDRSZ;
|
||||
else if( strncmp( azArg[1], "scratchmalloc", 3 )==0 ) testctrl = SQLITE_TESTCTRL_SCRATCHMALLOC;
|
||||
else testctrl = atoi(azArg[1]);
|
||||
|
||||
/* convert testctrl text option to value. allow any unique prefix
|
||||
** of the option name, or a numerical value. */
|
||||
n = strlen(azArg[1]);
|
||||
for(i=0; i<sizeof(aCtrl)/sizeof(aCtrl[0]); i++){
|
||||
if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
|
||||
if( testctrl<0 ){
|
||||
testctrl = aCtrl[i].ctrlCode;
|
||||
}else{
|
||||
fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]);
|
||||
testctrl = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( testctrl<0 ) testctrl = atoi(azArg[1]);
|
||||
if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
|
||||
fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
|
||||
}else{
|
||||
@@ -2208,7 +2225,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
rc = sqlite3_test_control(testctrl, p->db, opt);
|
||||
printf("%d (0x%08x)\n", rc, rc);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2232,7 +2250,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
printf("%d (0x%08x)\n", rc, rc);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single unsigned int option\n", azArg[1]);
|
||||
fprintf(stderr,"Error: testctrl %s takes a single unsigned"
|
||||
" int option\n", azArg[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2244,7 +2263,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
printf("%d (0x%08x)\n", rc, rc);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n", azArg[1]);
|
||||
fprintf(stderr,"Error: testctrl %s takes a single int option\n",
|
||||
azArg[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2256,7 +2276,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
printf("%d (0x%08x)\n", rc, rc);
|
||||
} else {
|
||||
fprintf(stderr,"Error: testctrl %s takes a single char * option\n", azArg[1]);
|
||||
fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
|
||||
azArg[1]);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
@@ -2266,7 +2287,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS:
|
||||
case SQLITE_TESTCTRL_SCRATCHMALLOC:
|
||||
default:
|
||||
fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n", azArg[1]);
|
||||
fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
|
||||
azArg[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2277,7 +2299,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
sqlite3_busy_timeout(p->db, atoi(azArg[1]));
|
||||
}else
|
||||
|
||||
if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0 && nArg==2 ){
|
||||
if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
|
||||
&& nArg==2
|
||||
){
|
||||
enableTimer = booleanValue(azArg[1]);
|
||||
}else
|
||||
|
||||
@@ -2464,7 +2488,9 @@ static int process_input(struct callback_data *p, FILE *in){
|
||||
}
|
||||
}
|
||||
if( zSql ){
|
||||
if( !_all_whitespace(zSql) ) fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
|
||||
if( !_all_whitespace(zSql) ){
|
||||
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
|
||||
}
|
||||
free(zSql);
|
||||
}
|
||||
free(zLine);
|
||||
@@ -2600,6 +2626,10 @@ static const char zOptions[] =
|
||||
" -stats print memory stats before each finalize\n"
|
||||
" -nullvalue 'text' set text string for NULL values\n"
|
||||
" -version show SQLite version\n"
|
||||
" -vfs NAME use NAME as the default VFS\n"
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
" -vfstrace enable tracing of all VFS calls\n"
|
||||
#endif
|
||||
;
|
||||
static void usage(int showDetail){
|
||||
fprintf(stderr,
|
||||
@@ -2684,6 +2714,25 @@ int main(int argc, char **argv){
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_VFSTRACE
|
||||
}else if( strcmp(argv[i],"-vfstrace")==0 ){
|
||||
extern int vfstrace_register(
|
||||
const char *zTraceName,
|
||||
const char *zOldVfsName,
|
||||
int (*xOut)(const char*,void*),
|
||||
void *pOutArg,
|
||||
int makeDefault
|
||||
);
|
||||
vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
|
||||
#endif
|
||||
}else if( strcmp(argv[i],"-vfs")==0 ){
|
||||
sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
|
||||
if( pVfs ){
|
||||
sqlite3_vfs_register(pVfs, 1);
|
||||
}else{
|
||||
fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( i<argc ){
|
||||
@@ -2792,6 +2841,10 @@ int main(int argc, char **argv){
|
||||
stdin_is_interactive = 0;
|
||||
}else if( strcmp(z,"-heap")==0 ){
|
||||
i++;
|
||||
}else if( strcmp(z,"-vfs")==0 ){
|
||||
i++;
|
||||
}else if( strcmp(z,"-vfstrace")==0 ){
|
||||
i++;
|
||||
}else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
|
||||
usage(1);
|
||||
}else{
|
||||
|
@@ -893,10 +893,22 @@ typedef struct sqlite3_mutex sqlite3_mutex;
|
||||
** date and time if that method is available (if iVersion is 2 or
|
||||
** greater and the function pointer is not NULL) and will fall back
|
||||
** to xCurrentTime() if xCurrentTimeInt64() is unavailable.
|
||||
**
|
||||
** ^The xSetSystemCall(), xGetSystemCall(), and xNestSystemCall() interfaces
|
||||
** are not used by the SQLite core. These optional interfaces are provided
|
||||
** by some VFSes to facilitate testing of the VFS code. By overriding
|
||||
** system calls with functions under its control, a test program can
|
||||
** simulate faults and error conditions that would otherwise be difficult
|
||||
** or impossible to induce. The set of system calls that can be overridden
|
||||
** varies from one VFS to another, and from one version of the same VFS to the
|
||||
** next. Applications that use these interfaces must be prepared for any
|
||||
** or all of these interfaces to be NULL or for their behavior to change
|
||||
** from one release to the next. Applications must not attempt to access
|
||||
** any of these methods if the iVersion of the VFS is less than 3.
|
||||
*/
|
||||
typedef struct sqlite3_vfs sqlite3_vfs;
|
||||
struct sqlite3_vfs {
|
||||
int iVersion; /* Structure version number (currently 2) */
|
||||
int iVersion; /* Structure version number (currently 3) */
|
||||
int szOsFile; /* Size of subclassed sqlite3_file */
|
||||
int mxPathname; /* Maximum file pathname length */
|
||||
sqlite3_vfs *pNext; /* Next registered VFS */
|
||||
@@ -922,6 +934,13 @@ struct sqlite3_vfs {
|
||||
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
|
||||
/*
|
||||
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
|
||||
** Those below are for version 3 and greater.
|
||||
*/
|
||||
int (*xSetSystemCall)(sqlite3_vfs*, const char *zName, void *pFunc);
|
||||
void *(*xGetSystemCall)(sqlite3_vfs*, const char *zName);
|
||||
const char *(*xNextSystemCall)(sqlite3_vfs*, const char *zName);
|
||||
/*
|
||||
** The methods above are in versions 1 through 3 of the sqlite_vfs object.
|
||||
** New fields may be appended in figure versions. The iVersion
|
||||
** value will increment whenever this happens.
|
||||
*/
|
||||
@@ -1341,7 +1360,9 @@ struct sqlite3_mem_methods {
|
||||
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
|
||||
** allocator is engaged to handle all of SQLites memory allocation needs.
|
||||
** The first pointer (the memory pointer) must be aligned to an 8-byte
|
||||
** boundary or subsequent behavior of SQLite will be undefined.</dd>
|
||||
** boundary or subsequent behavior of SQLite will be undefined.
|
||||
** The minimum allocation size is capped at 2^12. Reasonable values
|
||||
** for the minimum allocation size are 2^5 through 2^8.</dd>
|
||||
**
|
||||
** <dt>SQLITE_CONFIG_MUTEX</dt>
|
||||
** <dd> ^(This option takes a single argument which is a pointer to an
|
||||
|
@@ -1629,7 +1629,7 @@ struct Expr {
|
||||
u16 flags; /* Various flags. EP_* See below */
|
||||
union {
|
||||
char *zToken; /* Token value. Zero terminated and dequoted */
|
||||
int iValue; /* Integer value if EP_IntValue */
|
||||
int iValue; /* Non-negative integer value if EP_IntValue */
|
||||
} u;
|
||||
|
||||
/* If the EP_TokenOnly flag is set in the Expr.flags mask, then no
|
||||
@@ -2911,6 +2911,10 @@ Expr *sqlite3ExprSetCollByToken(Parse *pParse, Expr*, Token*);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
int sqlite3CheckObjectName(Parse *, const char *);
|
||||
void sqlite3VdbeSetChanges(sqlite3 *, int);
|
||||
int sqlite3AddInt64(i64*,i64);
|
||||
int sqlite3SubInt64(i64*,i64);
|
||||
int sqlite3MulInt64(i64*,i64);
|
||||
int sqlite3AbsInt32(int);
|
||||
|
||||
const void *sqlite3ValueText(sqlite3_value*, u8);
|
||||
int sqlite3ValueBytes(sqlite3_value*, u8);
|
||||
|
@@ -475,6 +475,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
|
||||
Tcl_SetVar2(interp, "sqlite_options", "truncate_opt", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "unique_enforcement", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_OMIT_UTF16
|
||||
Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
770
src/test_vfstrace.c
Normal file
770
src/test_vfstrace.c
Normal file
@@ -0,0 +1,770 @@
|
||||
/*
|
||||
** 2011 March 16
|
||||
**
|
||||
** 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 contains code implements a VFS shim that writes diagnostic
|
||||
** output for each VFS call, similar to "strace".
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/*
|
||||
** An instance of this structure is attached to the each trace VFS to
|
||||
** provide auxiliary information.
|
||||
*/
|
||||
typedef struct vfstrace_info vfstrace_info;
|
||||
struct vfstrace_info {
|
||||
sqlite3_vfs *pRootVfs; /* The underlying real VFS */
|
||||
int (*xOut)(const char*, void*); /* Send output here */
|
||||
void *pOutArg; /* First argument to xOut */
|
||||
const char *zVfsName; /* Name of this trace-VFS */
|
||||
sqlite3_vfs *pTraceVfs; /* Pointer back to the trace VFS */
|
||||
};
|
||||
|
||||
/*
|
||||
** The sqlite3_file object for the trace VFS
|
||||
*/
|
||||
typedef struct vfstrace_file vfstrace_file;
|
||||
struct vfstrace_file {
|
||||
sqlite3_file base; /* Base class. Must be first */
|
||||
vfstrace_info *pInfo; /* The trace-VFS to which this file belongs */
|
||||
const char *zFName; /* Base name of the file */
|
||||
sqlite3_file *pReal; /* The real underlying file */
|
||||
};
|
||||
|
||||
/*
|
||||
** Method declarations for vfstrace_file.
|
||||
*/
|
||||
static int vfstraceClose(sqlite3_file*);
|
||||
static int vfstraceRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int vfstraceWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64);
|
||||
static int vfstraceTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int vfstraceSync(sqlite3_file*, int flags);
|
||||
static int vfstraceFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int vfstraceLock(sqlite3_file*, int);
|
||||
static int vfstraceUnlock(sqlite3_file*, int);
|
||||
static int vfstraceCheckReservedLock(sqlite3_file*, int *);
|
||||
static int vfstraceFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int vfstraceSectorSize(sqlite3_file*);
|
||||
static int vfstraceDeviceCharacteristics(sqlite3_file*);
|
||||
static int vfstraceShmLock(sqlite3_file*,int,int,int);
|
||||
static int vfstraceShmMap(sqlite3_file*,int,int,int, void volatile **);
|
||||
static void vfstraceShmBarrier(sqlite3_file*);
|
||||
static int vfstraceShmUnmap(sqlite3_file*,int);
|
||||
|
||||
/*
|
||||
** Method declarations for vfstrace_vfs.
|
||||
*/
|
||||
static int vfstraceOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int vfstraceDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int vfstraceAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
||||
static int vfstraceFullPathname(sqlite3_vfs*, const char *zName, int, char *);
|
||||
static void *vfstraceDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void vfstraceDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void (*vfstraceDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
|
||||
static void vfstraceDlClose(sqlite3_vfs*, void*);
|
||||
static int vfstraceRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
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 const char *vfstraceNextSystemCall(sqlite3_vfs*, const char *zName);
|
||||
|
||||
/*
|
||||
** Return a pointer to the tail of the pathname. Examples:
|
||||
**
|
||||
** /home/drh/xyzzy.txt -> xyzzy.txt
|
||||
** xyzzy.txt -> xyzzy.txt
|
||||
*/
|
||||
static const char *fileTail(const char *z){
|
||||
int i;
|
||||
if( z==0 ) return 0;
|
||||
i = strlen(z)-1;
|
||||
while( i>0 && z[i-1]!='/' ){ i--; }
|
||||
return &z[i];
|
||||
}
|
||||
|
||||
/*
|
||||
** Send trace output defined by zFormat and subsequent arguments.
|
||||
*/
|
||||
static void vfstrace_printf(
|
||||
vfstrace_info *pInfo,
|
||||
const char *zFormat,
|
||||
...
|
||||
){
|
||||
va_list ap;
|
||||
char *zMsg;
|
||||
va_start(ap, zFormat);
|
||||
zMsg = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
pInfo->xOut(zMsg, pInfo->pOutArg);
|
||||
sqlite3_free(zMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert value rc into a string and print it using zFormat. zFormat
|
||||
** should have exactly one %s
|
||||
*/
|
||||
static void vfstrace_print_errcode(
|
||||
vfstrace_info *pInfo,
|
||||
const char *zFormat,
|
||||
int rc
|
||||
){
|
||||
char zBuf[50];
|
||||
char *zVal;
|
||||
switch( rc ){
|
||||
case SQLITE_OK: zVal = "SQLITE_OK"; break;
|
||||
case SQLITE_ERROR: zVal = "SQLITE_ERROR"; break;
|
||||
case SQLITE_PERM: zVal = "SQLITE_PERM"; break;
|
||||
case SQLITE_ABORT: zVal = "SQLITE_ABORT"; break;
|
||||
case SQLITE_BUSY: zVal = "SQLITE_BUSY"; break;
|
||||
case SQLITE_NOMEM: zVal = "SQLITE_NOMEM"; break;
|
||||
case SQLITE_READONLY: zVal = "SQLITE_READONLY"; break;
|
||||
case SQLITE_INTERRUPT: zVal = "SQLITE_INTERRUPT"; break;
|
||||
case SQLITE_IOERR: zVal = "SQLITE_IOERR"; break;
|
||||
case SQLITE_CORRUPT: zVal = "SQLITE_CORRUPT"; break;
|
||||
case SQLITE_FULL: zVal = "SQLITE_FULL"; break;
|
||||
case SQLITE_CANTOPEN: zVal = "SQLITE_CANTOPEN"; break;
|
||||
case SQLITE_PROTOCOL: zVal = "SQLITE_PROTOCOL"; break;
|
||||
case SQLITE_EMPTY: zVal = "SQLITE_EMPTY"; break;
|
||||
case SQLITE_SCHEMA: zVal = "SQLITE_SCHEMA"; break;
|
||||
case SQLITE_CONSTRAINT: zVal = "SQLITE_CONSTRAINT"; break;
|
||||
case SQLITE_MISMATCH: zVal = "SQLITE_MISMATCH"; break;
|
||||
case SQLITE_MISUSE: zVal = "SQLITE_MISUSE"; break;
|
||||
case SQLITE_NOLFS: zVal = "SQLITE_NOLFS"; break;
|
||||
case SQLITE_IOERR_READ: zVal = "SQLITE_IOERR_READ"; break;
|
||||
case SQLITE_IOERR_SHORT_READ: zVal = "SQLITE_IOERR_SHORT_READ"; break;
|
||||
case SQLITE_IOERR_WRITE: zVal = "SQLITE_IOERR_WRITE"; break;
|
||||
case SQLITE_IOERR_FSYNC: zVal = "SQLITE_IOERR_FSYNC"; break;
|
||||
case SQLITE_IOERR_DIR_FSYNC: zVal = "SQLITE_IOERR_DIR_FSYNC"; break;
|
||||
case SQLITE_IOERR_TRUNCATE: zVal = "SQLITE_IOERR_TRUNCATE"; break;
|
||||
case SQLITE_IOERR_FSTAT: zVal = "SQLITE_IOERR_FSTAT"; break;
|
||||
case SQLITE_IOERR_UNLOCK: zVal = "SQLITE_IOERR_UNLOCK"; break;
|
||||
case SQLITE_IOERR_RDLOCK: zVal = "SQLITE_IOERR_RDLOCK"; break;
|
||||
case SQLITE_IOERR_DELETE: zVal = "SQLITE_IOERR_DELETE"; break;
|
||||
case SQLITE_IOERR_BLOCKED: zVal = "SQLITE_IOERR_BLOCKED"; break;
|
||||
case SQLITE_IOERR_NOMEM: zVal = "SQLITE_IOERR_NOMEM"; break;
|
||||
case SQLITE_IOERR_ACCESS: zVal = "SQLITE_IOERR_ACCESS"; break;
|
||||
case SQLITE_IOERR_CHECKRESERVEDLOCK:
|
||||
zVal = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break;
|
||||
case SQLITE_IOERR_LOCK: zVal = "SQLITE_IOERR_LOCK"; break;
|
||||
case SQLITE_IOERR_CLOSE: zVal = "SQLITE_IOERR_CLOSE"; break;
|
||||
case SQLITE_IOERR_DIR_CLOSE: zVal = "SQLITE_IOERR_DIR_CLOSE"; break;
|
||||
case SQLITE_IOERR_SHMOPEN: zVal = "SQLITE_IOERR_SHMOPEN"; break;
|
||||
case SQLITE_IOERR_SHMSIZE: zVal = "SQLITE_IOERR_SHMSIZE"; break;
|
||||
case SQLITE_IOERR_SHMLOCK: zVal = "SQLITE_IOERR_SHMLOCK"; break;
|
||||
case SQLITE_LOCKED_SHAREDCACHE: zVal = "SQLITE_LOCKED_SHAREDCACHE"; break;
|
||||
case SQLITE_BUSY_RECOVERY: zVal = "SQLITE_BUSY_RECOVERY"; break;
|
||||
case SQLITE_CANTOPEN_NOTEMPDIR: zVal = "SQLITE_CANTOPEN_NOTEMPDIR"; break;
|
||||
default: {
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
|
||||
zVal = zBuf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfstrace_printf(pInfo, zFormat, zVal);
|
||||
}
|
||||
|
||||
/*
|
||||
** Append to a buffer.
|
||||
*/
|
||||
static void strappend(char *z, int *pI, const char *zAppend){
|
||||
int i = *pI;
|
||||
while( zAppend[0] ){ z[i++] = *(zAppend++); }
|
||||
z[i] = 0;
|
||||
*pI = i;
|
||||
}
|
||||
|
||||
/*
|
||||
** Close an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceClose(sqlite3_file *pFile){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xClose(%s)", pInfo->zVfsName, p->zFName);
|
||||
rc = p->pReal->pMethods->xClose(p->pReal);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_free((void*)p->base.pMethods);
|
||||
p->base.pMethods = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xRead(%s,n=%d,ofst=%lld)",
|
||||
pInfo->zVfsName, p->zFName, iAmt, iOfst);
|
||||
rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xWrite(%s,n=%d,ofst=%lld)",
|
||||
pInfo->zVfsName, p->zFName, iAmt, iOfst);
|
||||
rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xTruncate(%s,%lld)", pInfo->zVfsName, p->zFName,
|
||||
size);
|
||||
rc = p->pReal->pMethods->xTruncate(p->pReal, size);
|
||||
vfstrace_printf(pInfo, " -> %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceSync(sqlite3_file *pFile, int flags){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
int i;
|
||||
char zBuf[100];
|
||||
memcpy(zBuf, "|0", 3);
|
||||
i = 0;
|
||||
if( flags & SQLITE_SYNC_FULL ) strappend(zBuf, &i, "|FULL");
|
||||
else if( flags & SQLITE_SYNC_NORMAL ) strappend(zBuf, &i, "|NORMAL");
|
||||
if( flags & SQLITE_SYNC_DATAONLY ) strappend(zBuf, &i, "|DATAONLY");
|
||||
if( flags & ~(SQLITE_SYNC_FULL|SQLITE_SYNC_DATAONLY) ){
|
||||
sqlite3_snprintf(sizeof(zBuf)-i, &zBuf[i], "|0x%x", flags);
|
||||
}
|
||||
vfstrace_printf(pInfo, "%s.xSync(%s,%s)", pInfo->zVfsName, p->zFName,
|
||||
&zBuf[1]);
|
||||
rc = p->pReal->pMethods->xSync(p->pReal, flags);
|
||||
vfstrace_printf(pInfo, " -> %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xFileSize(%s)", pInfo->zVfsName, p->zFName);
|
||||
rc = p->pReal->pMethods->xFileSize(p->pReal, pSize);
|
||||
vfstrace_print_errcode(pInfo, " -> %s,", rc);
|
||||
vfstrace_printf(pInfo, " size=%lld\n", *pSize);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the name of a lock.
|
||||
*/
|
||||
static const char *lockName(int eLock){
|
||||
const char *azLockNames[] = {
|
||||
"NONE", "SHARED", "RESERVED", "PENDING", "EXCLUSIVE"
|
||||
};
|
||||
if( eLock<0 || eLock>=sizeof(azLockNames)/sizeof(azLockNames[0]) ){
|
||||
return "???";
|
||||
}else{
|
||||
return azLockNames[eLock];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceLock(sqlite3_file *pFile, int eLock){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xLock(%s,%s)", pInfo->zVfsName, p->zFName,
|
||||
lockName(eLock));
|
||||
rc = p->pReal->pMethods->xLock(p->pReal, eLock);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceUnlock(sqlite3_file *pFile, int eLock){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xUnlock(%s,%s)", pInfo->zVfsName, p->zFName,
|
||||
lockName(eLock));
|
||||
rc = p->pReal->pMethods->xUnlock(p->pReal, eLock);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xCheckReservedLock(%s,%d)",
|
||||
pInfo->zVfsName, p->zFName);
|
||||
rc = p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
char zBuf[100];
|
||||
char *zOp;
|
||||
switch( op ){
|
||||
case SQLITE_FCNTL_LOCKSTATE: zOp = "LOCKSTATE"; break;
|
||||
case SQLITE_GET_LOCKPROXYFILE: zOp = "GET_LOCKPROXYFILE"; break;
|
||||
case SQLITE_SET_LOCKPROXYFILE: zOp = "SET_LOCKPROXYFILE"; break;
|
||||
case SQLITE_LAST_ERRNO: zOp = "LAST_ERRNO"; break;
|
||||
case SQLITE_FCNTL_SIZE_HINT: {
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "SIZE_HINT,%lld",
|
||||
*(sqlite3_int64*)pArg);
|
||||
zOp = zBuf;
|
||||
break;
|
||||
}
|
||||
case SQLITE_FCNTL_CHUNK_SIZE: {
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "CHUNK_SIZE,%d", *(int*)pArg);
|
||||
zOp = zBuf;
|
||||
break;
|
||||
}
|
||||
case SQLITE_FCNTL_FILE_POINTER: zOp = "FILE_POINTER"; break;
|
||||
case SQLITE_FCNTL_SYNC_OMITTED: zOp = "SYNC_OMITTED"; break;
|
||||
case 0xca093fa0: zOp = "DB_UNCHANGED"; break;
|
||||
default: {
|
||||
sqlite3_snprintf(sizeof zBuf, zBuf, "%d", op);
|
||||
zOp = zBuf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
vfstrace_printf(pInfo, "%s.xFileControl(%s,%s)",
|
||||
pInfo->zVfsName, p->zFName, zOp);
|
||||
rc = p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceSectorSize(sqlite3_file *pFile){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xSectorSize(%s)", pInfo->zVfsName, p->zFName);
|
||||
rc = p->pReal->pMethods->xSectorSize(p->pReal);
|
||||
vfstrace_printf(pInfo, " -> %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by an vfstrace-file.
|
||||
*/
|
||||
static int vfstraceDeviceCharacteristics(sqlite3_file *pFile){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDeviceCharacteristics(%s)",
|
||||
pInfo->zVfsName, p->zFName);
|
||||
rc = p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
|
||||
vfstrace_printf(pInfo, " -> 0x%08x\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Shared-memory operations.
|
||||
*/
|
||||
static int vfstraceShmLock(sqlite3_file *pFile, int ofst, int n, int flags){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
char zLck[100];
|
||||
int i = 0;
|
||||
memcpy(zLck, "|0", 3);
|
||||
if( flags & SQLITE_SHM_UNLOCK ) strappend(zLck, &i, "|UNLOCK");
|
||||
if( flags & SQLITE_SHM_LOCK ) strappend(zLck, &i, "|LOCK");
|
||||
if( flags & SQLITE_SHM_SHARED ) strappend(zLck, &i, "|SHARED");
|
||||
if( flags & SQLITE_SHM_EXCLUSIVE ) strappend(zLck, &i, "|EXCLUSIVE");
|
||||
if( flags & ~(0xf) ){
|
||||
sqlite3_snprintf(sizeof(zLck)-i, &zLck[i], "|0x%x", flags);
|
||||
}
|
||||
vfstrace_printf(pInfo, "%s.xShmLock(%s,ofst=%d,n=%d,%s)",
|
||||
pInfo->zVfsName, p->zFName, ofst, n, &zLck[1]);
|
||||
rc = p->pReal->pMethods->xShmLock(p->pReal, ofst, n, flags);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
static int vfstraceShmMap(
|
||||
sqlite3_file *pFile,
|
||||
int iRegion,
|
||||
int szRegion,
|
||||
int isWrite,
|
||||
void volatile **pp
|
||||
){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xShmMap(%s,iRegion=%d,szRegion=%d,isWrite=%d,*)",
|
||||
pInfo->zVfsName, p->zFName, iRegion, szRegion, isWrite);
|
||||
rc = p->pReal->pMethods->xShmMap(p->pReal, iRegion, szRegion, isWrite, pp);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
static void vfstraceShmBarrier(sqlite3_file *pFile){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
vfstrace_printf(pInfo, "%s.xShmBarrier(%s)\n", pInfo->zVfsName, p->zFName);
|
||||
p->pReal->pMethods->xShmBarrier(p->pReal);
|
||||
}
|
||||
static int vfstraceShmUnmap(sqlite3_file *pFile, int delFlag){
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = p->pInfo;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xShmUnmap(%s,delFlag=%d)",
|
||||
pInfo->zVfsName, p->zFName, delFlag);
|
||||
rc = p->pReal->pMethods->xShmUnmap(p->pReal, delFlag);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Open an vfstrace file handle.
|
||||
*/
|
||||
static int vfstraceOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
int rc;
|
||||
vfstrace_file *p = (vfstrace_file *)pFile;
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
p->pInfo = pInfo;
|
||||
p->zFName = zName ? fileTail(zName) : "<temp>";
|
||||
p->pReal = (sqlite3_file *)&p[1];
|
||||
rc = pRoot->xOpen(pRoot, zName, p->pReal, flags, pOutFlags);
|
||||
vfstrace_printf(pInfo, "%s.xOpen(%s,flags=0x%x)",
|
||||
pInfo->zVfsName, p->zFName, flags);
|
||||
if( p->pReal->pMethods ){
|
||||
sqlite3_io_methods *pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
const sqlite3_io_methods *pSub = p->pReal->pMethods;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->iVersion = pSub->iVersion;
|
||||
pNew->xClose = vfstraceClose;
|
||||
pNew->xRead = vfstraceRead;
|
||||
pNew->xWrite = vfstraceWrite;
|
||||
pNew->xTruncate = vfstraceTruncate;
|
||||
pNew->xSync = vfstraceSync;
|
||||
pNew->xFileSize = vfstraceFileSize;
|
||||
pNew->xLock = vfstraceLock;
|
||||
pNew->xUnlock = vfstraceUnlock;
|
||||
pNew->xCheckReservedLock = vfstraceCheckReservedLock;
|
||||
pNew->xFileControl = vfstraceFileControl;
|
||||
pNew->xSectorSize = vfstraceSectorSize;
|
||||
pNew->xDeviceCharacteristics = vfstraceDeviceCharacteristics;
|
||||
if( pNew->iVersion>=2 ){
|
||||
pNew->xShmMap = pSub->xShmMap ? vfstraceShmMap : 0;
|
||||
pNew->xShmLock = pSub->xShmLock ? vfstraceShmLock : 0;
|
||||
pNew->xShmBarrier = pSub->xShmBarrier ? vfstraceShmBarrier : 0;
|
||||
pNew->xShmUnmap = pSub->xShmUnmap ? vfstraceShmUnmap : 0;
|
||||
}
|
||||
pFile->pMethods = pNew;
|
||||
}
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
if( pOutFlags ){
|
||||
vfstrace_printf(pInfo, ", outFlags=0x%x\n", *pOutFlags);
|
||||
}else{
|
||||
vfstrace_printf(pInfo, "\n");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file located at zPath. If the dirSync argument is true,
|
||||
** ensure the file-system modifications are synced to disk before
|
||||
** returning.
|
||||
*/
|
||||
static int vfstraceDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
|
||||
pInfo->zVfsName, zPath, dirSync);
|
||||
rc = pRoot->xDelete(pRoot, zPath, dirSync);
|
||||
vfstrace_print_errcode(pInfo, " -> %s\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Test for access permissions. Return true if the requested permission
|
||||
** is available, or false otherwise.
|
||||
*/
|
||||
static int vfstraceAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
|
||||
pInfo->zVfsName, zPath, flags);
|
||||
rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
vfstrace_printf(pInfo, ", out=%d\n", *pResOut);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate buffer zOut with the full canonical pathname corresponding
|
||||
** to the pathname in zPath. zOut is guaranteed to point to a buffer
|
||||
** of at least (DEVSYM_MAX_PATHNAME+1) bytes.
|
||||
*/
|
||||
static int vfstraceFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
int rc;
|
||||
vfstrace_printf(pInfo, "%s.xFullPathname(\"%s\")",
|
||||
pInfo->zVfsName, zPath);
|
||||
rc = pRoot->xFullPathname(pRoot, zPath, nOut, zOut);
|
||||
vfstrace_print_errcode(pInfo, " -> %s", rc);
|
||||
vfstrace_printf(pInfo, ", out=\"%.*s\"\n", nOut, zOut);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Open the dynamic library located at zPath and return a handle.
|
||||
*/
|
||||
static void *vfstraceDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
vfstrace_printf(pInfo, "%s.xDlOpen(\"%s\")\n", pInfo->zVfsName, zPath);
|
||||
return pRoot->xDlOpen(pRoot, zPath);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer zErrMsg (size nByte bytes) with a human readable
|
||||
** utf-8 string describing the most recent error encountered associated
|
||||
** with dynamic libraries.
|
||||
*/
|
||||
static void vfstraceDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
vfstrace_printf(pInfo, "%s.xDlError(%d)", pInfo->zVfsName, nByte);
|
||||
pRoot->xDlError(pRoot, nByte, zErrMsg);
|
||||
vfstrace_printf(pInfo, " -> \"%s\"", zErrMsg);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
|
||||
*/
|
||||
static void (*vfstraceDlSym(sqlite3_vfs *pVfs,void *p,const char *zSym))(void){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
vfstrace_printf(pInfo, "%s.xDlSym(\"%s\")\n", pInfo->zVfsName, zSym);
|
||||
return pRoot->xDlSym(pRoot, p, zSym);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the dynamic library handle pHandle.
|
||||
*/
|
||||
static void vfstraceDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
vfstrace_printf(pInfo, "%s.xDlOpen()\n", pInfo->zVfsName);
|
||||
pRoot->xDlClose(pRoot, pHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** Populate the buffer pointed to by zBufOut with nByte bytes of
|
||||
** random data.
|
||||
*/
|
||||
static int vfstraceRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
vfstrace_printf(pInfo, "%s.xRandomness(%d)\n", pInfo->zVfsName, nByte);
|
||||
return pRoot->xRandomness(pRoot, nByte, zBufOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sleep for nMicro microseconds. Return the number of microseconds
|
||||
** actually slept.
|
||||
*/
|
||||
static int vfstraceSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xSleep(pRoot, nMicro);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current time as a Julian Day number in *pTimeOut.
|
||||
*/
|
||||
static int vfstraceCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xCurrentTime(pRoot, pTimeOut);
|
||||
}
|
||||
static int vfstraceCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xCurrentTimeInt64(pRoot, pTimeOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return th3 emost recent error code and message
|
||||
*/
|
||||
static int vfstraceGetLastError(sqlite3_vfs *pVfs, int iErr, char *zErr){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xGetLastError(pRoot, iErr, zErr);
|
||||
}
|
||||
|
||||
/*
|
||||
** Override system calls.
|
||||
*/
|
||||
static int vfstraceSetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
void *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){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xGetSystemCall(pRoot, zName);
|
||||
}
|
||||
static const char *vfstraceNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
|
||||
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
|
||||
sqlite3_vfs *pRoot = pInfo->pRootVfs;
|
||||
return pRoot->xNextSystemCall(pRoot, zName);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Clients invoke this routine to construct a new trace-vfs shim.
|
||||
**
|
||||
** Return SQLITE_OK on success.
|
||||
**
|
||||
** SQLITE_NOMEM is returned in the case of a memory allocation error.
|
||||
** SQLITE_NOTFOUND is returned if zOldVfsName does not exist.
|
||||
*/
|
||||
int vfstrace_register(
|
||||
const char *zTraceName, /* Name of the newly constructed VFS */
|
||||
const char *zOldVfsName, /* Name of the underlying VFS */
|
||||
int (*xOut)(const char*,void*), /* Output routine. ex: fputs */
|
||||
void *pOutArg, /* 2nd argument to xOut. ex: stderr */
|
||||
int makeDefault /* True to make the new VFS the default */
|
||||
){
|
||||
sqlite3_vfs *pNew;
|
||||
sqlite3_vfs *pRoot;
|
||||
vfstrace_info *pInfo;
|
||||
int nName;
|
||||
int nByte;
|
||||
|
||||
pRoot = sqlite3_vfs_find(zOldVfsName);
|
||||
if( pRoot==0 ) return SQLITE_NOTFOUND;
|
||||
nName = strlen(zTraceName);
|
||||
nByte = sizeof(*pNew) + sizeof(*pInfo) + nName + 1;
|
||||
pNew = sqlite3_malloc( nByte );
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, nByte);
|
||||
pInfo = (vfstrace_info*)&pNew[1];
|
||||
pNew->iVersion = pRoot->iVersion;
|
||||
pNew->szOsFile = pRoot->szOsFile + sizeof(vfstrace_file);
|
||||
pNew->mxPathname = pRoot->mxPathname;
|
||||
pNew->zName = (char*)&pInfo[1];
|
||||
memcpy((char*)&pInfo[1], zTraceName, nName+1);
|
||||
pNew->pAppData = pInfo;
|
||||
pNew->xOpen = vfstraceOpen;
|
||||
pNew->xDelete = vfstraceDelete;
|
||||
pNew->xAccess = vfstraceAccess;
|
||||
pNew->xFullPathname = vfstraceFullPathname;
|
||||
pNew->xDlOpen = pRoot->xDlOpen==0 ? 0 : vfstraceDlOpen;
|
||||
pNew->xDlError = pRoot->xDlError==0 ? 0 : vfstraceDlError;
|
||||
pNew->xDlSym = pRoot->xDlSym==0 ? 0 : vfstraceDlSym;
|
||||
pNew->xDlClose = pRoot->xDlClose==0 ? 0 : vfstraceDlClose;
|
||||
pNew->xRandomness = vfstraceRandomness;
|
||||
pNew->xSleep = vfstraceSleep;
|
||||
pNew->xCurrentTime = vfstraceCurrentTime;
|
||||
pNew->xGetLastError = pRoot->xGetLastError==0 ? 0 : vfstraceGetLastError;
|
||||
if( pNew->iVersion>=2 ){
|
||||
pNew->xCurrentTimeInt64 = pRoot->xCurrentTimeInt64==0 ? 0 :
|
||||
vfstraceCurrentTimeInt64;
|
||||
if( pNew->iVersion>=3 ){
|
||||
pNew->xSetSystemCall = pRoot->xSetSystemCall==0 ? 0 :
|
||||
vfstraceSetSystemCall;
|
||||
pNew->xGetSystemCall = pRoot->xGetSystemCall==0 ? 0 :
|
||||
vfstraceGetSystemCall;
|
||||
pNew->xNextSystemCall = pRoot->xNextSystemCall==0 ? 0 :
|
||||
vfstraceNextSystemCall;
|
||||
}
|
||||
}
|
||||
pInfo->pRootVfs = pRoot;
|
||||
pInfo->xOut = xOut;
|
||||
pInfo->pOutArg = pOutArg;
|
||||
pInfo->zVfsName = pNew->zName;
|
||||
pInfo->pTraceVfs = pNew;
|
||||
vfstrace_printf(pInfo, "%s.enabled_for(\"%s\")\n",
|
||||
pInfo->zVfsName, pRoot->zName);
|
||||
return sqlite3_vfs_register(pNew, makeDefault);
|
||||
}
|
@@ -262,7 +262,6 @@ void sqlite3FinishTrigger(
|
||||
int iDb; /* Database containing the trigger */
|
||||
Token nameToken; /* Trigger name for error reporting */
|
||||
|
||||
pTrig = pParse->pNewTrigger;
|
||||
pParse->pNewTrigger = 0;
|
||||
if( NEVER(pParse->nErr) || !pTrig ) goto triggerfinish_cleanup;
|
||||
zName = pTrig->zName;
|
||||
|
@@ -128,7 +128,6 @@ void sqlite3Update(
|
||||
int regNew;
|
||||
int regOld = 0;
|
||||
int regRowSet = 0; /* Rowset of rows to be updated */
|
||||
int regRec; /* Register used for new table record to insert */
|
||||
|
||||
memset(&sContext, 0, sizeof(sContext));
|
||||
db = pParse->db;
|
||||
@@ -286,7 +285,6 @@ void sqlite3Update(
|
||||
}
|
||||
regNew = pParse->nMem + 1;
|
||||
pParse->nMem += pTab->nCol;
|
||||
regRec = ++pParse->nMem;
|
||||
|
||||
/* Start the view context. */
|
||||
if( isView ){
|
||||
@@ -396,7 +394,7 @@ void sqlite3Update(
|
||||
pTrigger, pChanges, 0, TRIGGER_BEFORE|TRIGGER_AFTER, pTab, onError
|
||||
);
|
||||
for(i=0; i<pTab->nCol; i++){
|
||||
if( aXRef[i]<0 || oldmask==0xffffffff || (oldmask & (1<<i)) ){
|
||||
if( aXRef[i]<0 || oldmask==0xffffffff || (i<32 && (oldmask & (1<<i))) ){
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, i, regOld+i);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regOld+i);
|
||||
|
124
src/util.c
124
src/util.c
@@ -441,14 +441,17 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
|
||||
|
||||
/*
|
||||
** Convert zNum to a 64-bit signed integer and write
|
||||
** the value of the integer into *pNum.
|
||||
** If zNum is exactly 9223372036854665808, return 2.
|
||||
** This is a special case as the context will determine
|
||||
** if it is too big (used as a negative).
|
||||
** If zNum is not an integer or is an integer that
|
||||
** is too large to be expressed with 64 bits,
|
||||
** then return 1. Otherwise return 0.
|
||||
** Convert zNum to a 64-bit signed integer.
|
||||
**
|
||||
** If the zNum value is representable as a 64-bit twos-complement
|
||||
** integer, then write that value into *pNum and return 0.
|
||||
**
|
||||
** If zNum is exactly 9223372036854665808, return 2. This special
|
||||
** case is broken out because while 9223372036854665808 cannot be a
|
||||
** signed 64-bit integer, its negative -9223372036854665808 can be.
|
||||
**
|
||||
** If zNum is too big for a 64-bit integer and is not
|
||||
** 9223372036854665808 then return 1.
|
||||
**
|
||||
** length is the number of bytes in the string (bytes, not characters).
|
||||
** The string is not necessarily zero-terminated. The encoding is
|
||||
@@ -456,7 +459,7 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
*/
|
||||
int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
int incr = (enc==SQLITE_UTF8?1:2);
|
||||
i64 v = 0;
|
||||
u64 u = 0;
|
||||
int neg = 0; /* assume positive */
|
||||
int i;
|
||||
int c = 0;
|
||||
@@ -464,20 +467,26 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
const char *zEnd = zNum + length;
|
||||
if( enc==SQLITE_UTF16BE ) zNum++;
|
||||
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
|
||||
if( zNum>=zEnd ) goto do_atoi_calc;
|
||||
if( zNum<zEnd ){
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum+=incr;
|
||||
}else if( *zNum=='+' ){
|
||||
zNum+=incr;
|
||||
}
|
||||
do_atoi_calc:
|
||||
}
|
||||
zStart = zNum;
|
||||
while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
|
||||
for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
|
||||
v = v*10 + c - '0';
|
||||
u = u*10 + c - '0';
|
||||
}
|
||||
if( u>LARGEST_INT64 ){
|
||||
*pNum = SMALLEST_INT64;
|
||||
}else if( neg ){
|
||||
*pNum = -(i64)u;
|
||||
}else{
|
||||
*pNum = (i64)u;
|
||||
}
|
||||
*pNum = neg ? -v : v;
|
||||
testcase( i==18 );
|
||||
testcase( i==19 );
|
||||
testcase( i==20 );
|
||||
@@ -487,14 +496,25 @@ do_atoi_calc:
|
||||
return 1;
|
||||
}else if( i<19*incr ){
|
||||
/* Less than 19 digits, so we know that it fits in 64 bits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return 0;
|
||||
}else{
|
||||
/* 19-digit numbers must be no larger than 9223372036854775807 if positive
|
||||
** or 9223372036854775808 if negative. Note that 9223372036854665808
|
||||
** is 2^63. Return 1 if to large */
|
||||
/* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */
|
||||
c = compare2pow63(zNum, incr);
|
||||
if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */
|
||||
return c<neg ? 0 : 1;
|
||||
if( c<0 ){
|
||||
/* zNum is less than 9223372036854775808 so it fits */
|
||||
assert( u<=LARGEST_INT64 );
|
||||
return 0;
|
||||
}else if( c>0 ){
|
||||
/* zNum is greater than 9223372036854775808 so it overflows */
|
||||
return 1;
|
||||
}else{
|
||||
/* zNum is exactly 9223372036854775808. Fits if negative. The
|
||||
** special case 2 overflow if positive */
|
||||
assert( u-1==LARGEST_INT64 );
|
||||
assert( (*pNum)==SMALLEST_INT64 );
|
||||
return neg ? 0 : 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1060,3 +1080,71 @@ int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to add, substract, or multiply the 64-bit signed value iB against
|
||||
** the other 64-bit signed integer at *pA and store the result in *pA.
|
||||
** Return 0 on success. Or if the operation would have resulted in an
|
||||
** overflow, leave *pA unchanged and return 1.
|
||||
*/
|
||||
int sqlite3AddInt64(i64 *pA, i64 iB){
|
||||
i64 iA = *pA;
|
||||
testcase( iA==0 ); testcase( iA==1 );
|
||||
testcase( iB==-1 ); testcase( iB==0 );
|
||||
if( iB>=0 ){
|
||||
testcase( iA>0 && LARGEST_INT64 - iA == iB );
|
||||
testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 );
|
||||
if( iA>0 && LARGEST_INT64 - iA < iB ) return 1;
|
||||
*pA += iB;
|
||||
}else{
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 );
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 );
|
||||
if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
|
||||
*pA += iB;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int sqlite3SubInt64(i64 *pA, i64 iB){
|
||||
testcase( iB==SMALLEST_INT64+1 );
|
||||
if( iB==SMALLEST_INT64 ){
|
||||
testcase( (*pA)==(-1) ); testcase( (*pA)==0 );
|
||||
if( (*pA)>=0 ) return 1;
|
||||
*pA -= iB;
|
||||
return 0;
|
||||
}else{
|
||||
return sqlite3AddInt64(pA, -iB);
|
||||
}
|
||||
}
|
||||
#define TWOPOWER32 (((i64)1)<<32)
|
||||
#define TWOPOWER31 (((i64)1)<<31)
|
||||
int sqlite3MulInt64(i64 *pA, i64 iB){
|
||||
i64 iA = *pA;
|
||||
i64 iA1, iA0, iB1, iB0, r;
|
||||
|
||||
iA1 = iA/TWOPOWER32;
|
||||
iA0 = iA % TWOPOWER32;
|
||||
iB1 = iB/TWOPOWER32;
|
||||
iB0 = iB % TWOPOWER32;
|
||||
if( iA1*iB1 != 0 ) return 1;
|
||||
assert( iA1*iB0==0 || iA0*iB1==0 );
|
||||
r = iA1*iB0 + iA0*iB1;
|
||||
testcase( r==(-TWOPOWER31)-1 );
|
||||
testcase( r==(-TWOPOWER31) );
|
||||
testcase( r==TWOPOWER31 );
|
||||
testcase( r==TWOPOWER31-1 );
|
||||
if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
|
||||
r *= TWOPOWER32;
|
||||
if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
|
||||
*pA = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Compute the absolute value of a 32-bit signed integer, of possible. Or
|
||||
** if the integer has a value of -2147483648, return +2147483647
|
||||
*/
|
||||
int sqlite3AbsInt32(int x){
|
||||
if( x>=0 ) return x;
|
||||
if( x==(int)0x80000000 ) return 0x7fffffff;
|
||||
return -x;
|
||||
}
|
||||
|
64
src/vdbe.c
64
src/vdbe.c
@@ -1246,19 +1246,12 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
iA = pIn1->u.i;
|
||||
iB = pIn2->u.i;
|
||||
switch( pOp->opcode ){
|
||||
case OP_Add: iB += iA; break;
|
||||
case OP_Subtract: iB -= iA; break;
|
||||
case OP_Multiply: iB *= iA; break;
|
||||
case OP_Add: if( sqlite3AddInt64(&iB,iA) ) goto fp_math; break;
|
||||
case OP_Subtract: if( sqlite3SubInt64(&iB,iA) ) goto fp_math; break;
|
||||
case OP_Multiply: if( sqlite3MulInt64(&iB,iA) ) goto fp_math; break;
|
||||
case OP_Divide: {
|
||||
if( iA==0 ) goto arithmetic_result_is_null;
|
||||
/* Dividing the largest possible negative 64-bit integer (1<<63) by
|
||||
** -1 returns an integer too large to store in a 64-bit data-type. On
|
||||
** some architectures, the value overflows to (1<<63). On others,
|
||||
** a SIGFPE is issued. The following statement normalizes this
|
||||
** behavior so that all architectures behave as if integer
|
||||
** overflow occurred.
|
||||
*/
|
||||
if( iA==-1 && iB==SMALLEST_INT64 ) iA = 1;
|
||||
if( iA==-1 && iB==SMALLEST_INT64 ) goto fp_math;
|
||||
iB /= iA;
|
||||
break;
|
||||
}
|
||||
@@ -1272,6 +1265,7 @@ case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
|
||||
pOut->u.i = iB;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
}else{
|
||||
fp_math:
|
||||
rA = sqlite3VdbeRealValue(pIn1);
|
||||
rB = sqlite3VdbeRealValue(pIn2);
|
||||
switch( pOp->opcode ){
|
||||
@@ -1466,8 +1460,10 @@ case OP_BitAnd: /* same as TK_BITAND, in1, in2, out3 */
|
||||
case OP_BitOr: /* same as TK_BITOR, in1, in2, out3 */
|
||||
case OP_ShiftLeft: /* same as TK_LSHIFT, in1, in2, out3 */
|
||||
case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
||||
i64 a;
|
||||
i64 b;
|
||||
i64 iA;
|
||||
u64 uA;
|
||||
i64 iB;
|
||||
u8 op;
|
||||
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
@@ -1476,16 +1472,38 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */
|
||||
sqlite3VdbeMemSetNull(pOut);
|
||||
break;
|
||||
}
|
||||
a = sqlite3VdbeIntValue(pIn2);
|
||||
b = sqlite3VdbeIntValue(pIn1);
|
||||
switch( pOp->opcode ){
|
||||
case OP_BitAnd: a &= b; break;
|
||||
case OP_BitOr: a |= b; break;
|
||||
case OP_ShiftLeft: a <<= b; break;
|
||||
default: assert( pOp->opcode==OP_ShiftRight );
|
||||
a >>= b; break;
|
||||
iA = sqlite3VdbeIntValue(pIn2);
|
||||
iB = sqlite3VdbeIntValue(pIn1);
|
||||
op = pOp->opcode;
|
||||
if( op==OP_BitAnd ){
|
||||
iA &= iB;
|
||||
}else if( op==OP_BitOr ){
|
||||
iA |= iB;
|
||||
}else if( iB!=0 ){
|
||||
assert( op==OP_ShiftRight || op==OP_ShiftLeft );
|
||||
|
||||
/* If shifting by a negative amount, shift in the other direction */
|
||||
if( iB<0 ){
|
||||
assert( OP_ShiftRight==OP_ShiftLeft+1 );
|
||||
op = 2*OP_ShiftLeft + 1 - op;
|
||||
iB = iB>(-64) ? -iB : 64;
|
||||
}
|
||||
pOut->u.i = a;
|
||||
|
||||
if( iB>=64 ){
|
||||
iA = (iA>=0 || op==OP_ShiftLeft) ? 0 : -1;
|
||||
}else{
|
||||
memcpy(&uA, &iA, sizeof(uA));
|
||||
if( op==OP_ShiftLeft ){
|
||||
uA <<= iB;
|
||||
}else{
|
||||
uA >>= iB;
|
||||
/* Sign-extend on a right shift of a negative number */
|
||||
if( iA<0 ) uA |= ((((u64)0xffffffff)<<32)|0xffffffff) << (64-iB);
|
||||
}
|
||||
memcpy(&iA, &uA, sizeof(iA));
|
||||
}
|
||||
}
|
||||
pOut->u.i = iA;
|
||||
MemSetTypeFlag(pOut, MEM_Int);
|
||||
break;
|
||||
}
|
||||
@@ -2411,7 +2429,6 @@ case OP_MakeRecord: {
|
||||
*/
|
||||
nData = 0; /* Number of bytes of data space */
|
||||
nHdr = 0; /* Number of bytes of header space */
|
||||
nByte = 0; /* Data space required for this record */
|
||||
nZero = 0; /* Number of zero bytes at the end of the record */
|
||||
nField = pOp->p1;
|
||||
zAffinity = pOp->p4.z;
|
||||
@@ -3685,7 +3702,6 @@ case OP_NewRowid: { /* out2-prerelease */
|
||||
** and try again, up to 100 times.
|
||||
*/
|
||||
assert( pC->isTable );
|
||||
cnt = 0;
|
||||
|
||||
#ifdef SQLITE_32BIT_ROWID
|
||||
# define MAX_ROWID 0x7fffffff
|
||||
|
@@ -702,13 +702,11 @@ static const Mem *columnNullValue(void){
|
||||
*/
|
||||
static Mem *columnMem(sqlite3_stmt *pStmt, int i){
|
||||
Vdbe *pVm;
|
||||
int vals;
|
||||
Mem *pOut;
|
||||
|
||||
pVm = (Vdbe *)pStmt;
|
||||
if( pVm && pVm->pResultSet!=0 && i<pVm->nResColumn && i>=0 ){
|
||||
sqlite3_mutex_enter(pVm->db->mutex);
|
||||
vals = sqlite3_data_count(pStmt);
|
||||
pOut = &pVm->pResultSet[i];
|
||||
}else{
|
||||
/* If the value passed as the second argument is out of range, return
|
||||
|
@@ -75,6 +75,7 @@ const char *sqlite3_sql(sqlite3_stmt *pStmt){
|
||||
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
|
||||
Vdbe tmp, *pTmp;
|
||||
char *zTmp;
|
||||
assert( pA->db==pB->db );
|
||||
tmp = *pA;
|
||||
*pA = *pB;
|
||||
*pB = tmp;
|
||||
@@ -1517,7 +1518,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *pFrame){
|
||||
*/
|
||||
static void closeAllCursors(Vdbe *p){
|
||||
if( p->pFrame ){
|
||||
VdbeFrame *pFrame = p->pFrame;
|
||||
VdbeFrame *pFrame;
|
||||
for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
|
||||
sqlite3VdbeFrameRestore(pFrame);
|
||||
}
|
||||
@@ -2497,7 +2498,13 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
||||
if( file_format>=4 && (i&1)==i ){
|
||||
return 8+(u32)i;
|
||||
}
|
||||
u = i<0 ? -i : i;
|
||||
if( i<0 ){
|
||||
if( i<(-MAX_6BYTE) ) return 6;
|
||||
/* Previous test prevents: u = -(-9223372036854775808) */
|
||||
u = -i;
|
||||
}else{
|
||||
u = i;
|
||||
}
|
||||
if( u<=127 ) return 1;
|
||||
if( u<=32767 ) return 2;
|
||||
if( u<=8388607 ) return 3;
|
||||
|
@@ -367,7 +367,7 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
|
||||
}else if( flags & MEM_Real ){
|
||||
return doubleToInt64(pMem->r);
|
||||
}else if( flags & (MEM_Str|MEM_Blob) ){
|
||||
i64 value;
|
||||
i64 value = 0;
|
||||
assert( pMem->z || pMem->n==0 );
|
||||
testcase( pMem->z==0 );
|
||||
sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
|
||||
@@ -1077,9 +1077,14 @@ int sqlite3ValueFromExpr(
|
||||
/* This branch happens for multiple negative signs. Ex: -(-5) */
|
||||
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
|
||||
sqlite3VdbeMemNumerify(pVal);
|
||||
pVal->u.i = -1 * pVal->u.i;
|
||||
/* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
|
||||
pVal->r = (double)-1 * pVal->r;
|
||||
if( pVal->u.i==SMALLEST_INT64 ){
|
||||
pVal->flags &= MEM_Int;
|
||||
pVal->flags |= MEM_Real;
|
||||
pVal->r = (double)LARGEST_INT64;
|
||||
}else{
|
||||
pVal->u.i = -pVal->u.i;
|
||||
}
|
||||
pVal->r = -pVal->r;
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, enc);
|
||||
}
|
||||
}else if( op==TK_NULL ){
|
||||
|
@@ -1649,7 +1649,6 @@ static int walCheckpoint(
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
mxPage = pWal->hdr.nPage;
|
||||
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
|
||||
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
|
30
src/where.c
30
src/where.c
@@ -2520,7 +2520,8 @@ range_est_fallback:
|
||||
** an equality constraint x=VALUE and where that VALUE occurs in
|
||||
** the histogram data. This only works when x is the left-most
|
||||
** column of an index and sqlite_stat2 histogram data is available
|
||||
** for that index.
|
||||
** for that index. When pExpr==NULL that means the constraint is
|
||||
** "x IS NULL" instead of "x=VALUE".
|
||||
**
|
||||
** Write the estimated row count into *pnRow and return SQLITE_OK.
|
||||
** If unable to make an estimate, leave *pnRow unchanged and return
|
||||
@@ -2545,8 +2546,12 @@ int whereEqualScanEst(
|
||||
|
||||
assert( p->aSample!=0 );
|
||||
aff = p->pTable->aCol[p->aiColumn[0]].affinity;
|
||||
if( pExpr ){
|
||||
rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
|
||||
if( rc ) goto whereEqualScanEst_cancel;
|
||||
}else{
|
||||
pRhs = sqlite3ValueNew(pParse->db);
|
||||
}
|
||||
if( pRhs==0 ) return SQLITE_NOTFOUND;
|
||||
rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
|
||||
if( rc ) goto whereEqualScanEst_cancel;
|
||||
@@ -2935,7 +2940,9 @@ static void bestBtreeIndex(
|
||||
** VALUE and how common that value is according to the histogram.
|
||||
*/
|
||||
if( nRow>(double)1 && nEq==1 && pFirstTerm!=0 ){
|
||||
if( pFirstTerm->eOperator==WO_EQ ){
|
||||
if( pFirstTerm->eOperator & (WO_EQ|WO_ISNULL) ){
|
||||
testcase( pFirstTerm->eOperator==WO_EQ );
|
||||
testcase( pFirstTerm->pOperator==WO_ISNULL );
|
||||
whereEqualScanEst(pParse, pProbe, pFirstTerm->pExpr->pRight, &nRow);
|
||||
}else if( pFirstTerm->eOperator==WO_IN && bInEst==0 ){
|
||||
whereInScanEst(pParse, pProbe, pFirstTerm->pExpr->x.pList, &nRow);
|
||||
@@ -4001,7 +4008,13 @@ static Bitmask codeOneLoopStart(
|
||||
/* Record the instruction used to terminate the loop. Disable
|
||||
** WHERE clause terms made redundant by the index range scan.
|
||||
*/
|
||||
pLevel->op = bRev ? OP_Prev : OP_Next;
|
||||
if( pLevel->plan.wsFlags & WHERE_UNIQUE ){
|
||||
pLevel->op = OP_Noop;
|
||||
}else if( bRev ){
|
||||
pLevel->op = OP_Prev;
|
||||
}else{
|
||||
pLevel->op = OP_Next;
|
||||
}
|
||||
pLevel->p1 = iIdxCur;
|
||||
}else
|
||||
|
||||
@@ -4047,7 +4060,6 @@ static Bitmask codeOneLoopStart(
|
||||
**
|
||||
*/
|
||||
WhereClause *pOrWc; /* The OR-clause broken out into subterms */
|
||||
WhereTerm *pFinal; /* Final subterm within the OR-clause. */
|
||||
SrcList *pOrTab; /* Shortened table list or OR-clause generation */
|
||||
|
||||
int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */
|
||||
@@ -4063,7 +4075,6 @@ static Bitmask codeOneLoopStart(
|
||||
assert( pTerm->eOperator==WO_OR );
|
||||
assert( (pTerm->wtFlags & TERM_ORINFO)!=0 );
|
||||
pOrWc = &pTerm->u.pOrInfo->wc;
|
||||
pFinal = &pOrWc->a[pOrWc->nTerm-1];
|
||||
pLevel->op = OP_Return;
|
||||
pLevel->p1 = regReturn;
|
||||
|
||||
@@ -4172,7 +4183,6 @@ static Bitmask codeOneLoopStart(
|
||||
** the use of indices become tests that are evaluated against each row of
|
||||
** the relevant input tables.
|
||||
*/
|
||||
k = 0;
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* IMP: R-30575-11662 */
|
||||
@@ -4190,7 +4200,6 @@ static Bitmask codeOneLoopStart(
|
||||
continue;
|
||||
}
|
||||
sqlite3ExprIfFalse(pParse, pE, addrCont, SQLITE_JUMPIFNULL);
|
||||
k = 1;
|
||||
pTerm->wtFlags |= TERM_CODED;
|
||||
}
|
||||
|
||||
@@ -4498,8 +4507,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** clause.
|
||||
*/
|
||||
notReady = ~(Bitmask)0;
|
||||
pTabItem = pTabList->a;
|
||||
pLevel = pWInfo->a;
|
||||
andFlags = ~0;
|
||||
WHERETRACE(("*** Optimizer Start ***\n"));
|
||||
for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
|
||||
@@ -4610,8 +4617,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** (1) The table must not depend on other tables that have not
|
||||
** yet run.
|
||||
**
|
||||
** (2) A full-table-scan plan cannot supercede another plan unless
|
||||
** it is an "optimal" plan as defined above.
|
||||
** (2) A full-table-scan plan cannot supercede indexed plan unless
|
||||
** the full-table-scan is an "optimal" plan as defined above.
|
||||
**
|
||||
** (3) All tables have an INDEXED BY clause or this table lacks an
|
||||
** INDEXED BY clause or this table uses the specific
|
||||
@@ -4627,6 +4634,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
*/
|
||||
if( (sCost.used¬Ready)==0 /* (1) */
|
||||
&& (bestJ<0 || (notIndexed&m)!=0 /* (2) */
|
||||
|| (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
|
||||
|| (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
|
||||
&& (nUnconstrained==0 || pTabItem->pIndex==0 /* (3) */
|
||||
|| NEVER((sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
|
||||
|
@@ -164,6 +164,8 @@ foreach {testid where index rows} {
|
||||
301 {y=1} t1y 50
|
||||
302 {y=0.1} t1y 50
|
||||
|
||||
400 {x IS NULL} t1x 400
|
||||
|
||||
} {
|
||||
# Verify that the expected index is used with the expected row count
|
||||
do_test analyze5-1.${testid}a {
|
||||
@@ -190,5 +192,48 @@ foreach {testid where index rows} {
|
||||
} {ok}
|
||||
}
|
||||
|
||||
# Increase the number of NULLs in column x
|
||||
#
|
||||
db eval {
|
||||
UPDATE t1 SET x=NULL;
|
||||
UPDATE t1 SET x=rowid
|
||||
WHERE rowid IN (SELECT rowid FROM t1 ORDER BY random() LIMIT 5);
|
||||
ANALYZE;
|
||||
}
|
||||
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
foreach {testid where index rows} {
|
||||
500 {x IS NULL AND u='charlie'} t1u 20
|
||||
501 {x=1 AND u='charlie'} t1x 5
|
||||
502 {x IS NULL} {} 100
|
||||
503 {x=1} t1x 50
|
||||
504 {x IS NOT NULL} t1x 25
|
||||
|
||||
} {
|
||||
# Verify that the expected index is used with the expected row count
|
||||
do_test analyze5-1.${testid}a {
|
||||
set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3]
|
||||
set idx {}
|
||||
regexp {INDEX (t1.) } $x all idx
|
||||
regexp {~([0-9]+) rows} $x all nrow
|
||||
list $idx $nrow
|
||||
} [list $index $rows]
|
||||
|
||||
# Verify that the same result is achieved regardless of whether or not
|
||||
# the index is used
|
||||
do_test analyze5-1.${testid}b {
|
||||
set w2 [string map {y +y z +z} $where]
|
||||
set a1 [db eval "SELECT rowid FROM t1 NOT INDEXED WHERE $w2\
|
||||
ORDER BY +rowid"]
|
||||
set a2 [db eval "SELECT rowid FROM t1 WHERE $where ORDER BY +rowid"]
|
||||
if {$a1==$a2} {
|
||||
set res ok
|
||||
} else {
|
||||
set res "a1=\[$a1\] a2=\[$a2\]"
|
||||
}
|
||||
set res
|
||||
} {ok}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
74
test/analyze6.test
Normal file
74
test/analyze6.test
Normal file
@@ -0,0 +1,74 @@
|
||||
# 2011 March 3
|
||||
#
|
||||
# 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 tests for SQLite library. The focus of the tests
|
||||
# in this file a corner-case query planner optimization involving the
|
||||
# join order of two tables of different sizes.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat2 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix analyze6
|
||||
|
||||
proc eqp {sql {db db}} {
|
||||
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
|
||||
}
|
||||
|
||||
do_test analyze6-1.0 {
|
||||
db eval {
|
||||
CREATE TABLE cat(x INT);
|
||||
CREATE UNIQUE INDEX catx ON cat(x);
|
||||
/* Give cat 16 unique integers */
|
||||
INSERT INTO cat VALUES(1);
|
||||
INSERT INTO cat VALUES(2);
|
||||
INSERT INTO cat SELECT x+2 FROM cat;
|
||||
INSERT INTO cat SELECT x+4 FROM cat;
|
||||
INSERT INTO cat SELECT x+8 FROM cat;
|
||||
|
||||
CREATE TABLE ev(y INT);
|
||||
CREATE INDEX evy ON ev(y);
|
||||
/* ev will hold 32 copies of 16 integers found in cat */
|
||||
INSERT INTO ev SELECT x FROM cat;
|
||||
INSERT INTO ev SELECT x FROM cat;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
INSERT INTO ev SELECT y FROM ev;
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM cat;
|
||||
SELECT count(*) FROM ev;
|
||||
}
|
||||
} {16 512}
|
||||
|
||||
# The lowest cost plan is to scan CAT and for each integer there, do a single
|
||||
# lookup of the first corresponding entry in EV then read off the equal values
|
||||
# in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would
|
||||
# have used EV for the outer loop instead of CAT - which was about 3x slower.)
|
||||
#
|
||||
do_test analyze6-1.1 {
|
||||
eqp {SELECT count(*) FROM ev, cat WHERE x=y}
|
||||
} {0 0 1 {SCAN TABLE cat (~16 rows)} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}}
|
||||
|
||||
# The same plan is chosen regardless of the order of the tables in the
|
||||
# FROM clause.
|
||||
#
|
||||
do_test analyze6-1.2 {
|
||||
eqp {SELECT count(*) FROM cat, ev WHERE x=y}
|
||||
} {0 0 0 {SCAN TABLE cat (~16 rows)} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?) (~32 rows)}}
|
||||
|
||||
|
||||
finish_test
|
119
test/expr.test
119
test/expr.test
@@ -82,8 +82,18 @@ test_expr expr-1.43 {i1=1, i2=2} {i1&i2} {0}
|
||||
test_expr expr-1.43b {i1=1, i2=2} {4&5} {4}
|
||||
test_expr expr-1.44 {i1=1} {~i1} {-2}
|
||||
test_expr expr-1.44b {i1=NULL} {~i1} {{}}
|
||||
test_expr expr-1.45 {i1=1, i2=3} {i1<<i2} {8}
|
||||
test_expr expr-1.46 {i1=32, i2=3} {i1>>i2} {4}
|
||||
test_expr expr-1.45a {i1=1, i2=3} {i1<<i2} {8}
|
||||
test_expr expr-1.45b {i1=1, i2=-3} {i1>>i2} {8}
|
||||
test_expr expr-1.45c {i1=1, i2=0} {i1<<i2} {1}
|
||||
test_expr expr-1.45d {i1=1, i2=62} {i1<<i2} {4611686018427387904}
|
||||
test_expr expr-1.45e {i1=1, i2=63} {i1<<i2} {-9223372036854775808}
|
||||
test_expr expr-1.45f {i1=1, i2=64} {i1<<i2} {0}
|
||||
test_expr expr-1.45g {i1=32, i2=-9223372036854775808} {i1>>i2} {0}
|
||||
test_expr expr-1.46a {i1=32, i2=3} {i1>>i2} {4}
|
||||
test_expr expr-1.46b {i1=32, i2=6} {i1>>i2} {0}
|
||||
test_expr expr-1.46c {i1=-32, i2=3} {i1>>i2} {-4}
|
||||
test_expr expr-1.46d {i1=-32, i2=100} {i1>>i2} {-1}
|
||||
test_expr expr-1.46e {i1=32, i2=-3} {i1>>i2} {256}
|
||||
test_expr expr-1.47 {i1=9999999999, i2=8888888888} {i1<i2} 0
|
||||
test_expr expr-1.48 {i1=9999999999, i2=8888888888} {i1=i2} 0
|
||||
test_expr expr-1.49 {i1=9999999999, i2=8888888888} {i1>i2} 1
|
||||
@@ -154,10 +164,10 @@ ifcapable floatingpoint {
|
||||
}
|
||||
|
||||
if {[working_64bit_int]} {
|
||||
test_expr expr-1.106 {i1=0} {(1<<63)/-1} -9223372036854775808
|
||||
test_expr expr-1.106 {i1=0} {-9223372036854775808/-1} 9.22337203685478e+18
|
||||
}
|
||||
|
||||
test_expr expr-1.107 {i1=0} {(1<<63)%-1} 0
|
||||
test_expr expr-1.107 {i1=0} {-9223372036854775808%-1} 0
|
||||
test_expr expr-1.108 {i1=0} {1%0} {{}}
|
||||
test_expr expr-1.109 {i1=0} {1/0} {{}}
|
||||
|
||||
@@ -190,6 +200,107 @@ test_expr expr-1.125 {i1=6, i2=NULL} \
|
||||
test_expr expr-1.126 {i1=8, i2=8} \
|
||||
{CASE WHEN i1 IS NOT i2 THEN 'yes' ELSE 'no' END} no
|
||||
|
||||
ifcapable floatingpoint {if {[working_64bit_int]} {
|
||||
test_expr expr-1.200\
|
||||
{i1=9223372036854775806, i2=1} {i1+i2} 9223372036854775807
|
||||
test_expr expr-1.201\
|
||||
{i1=9223372036854775806, i2=2} {i1+i2} 9.22337203685478e+18
|
||||
test_expr expr-1.202\
|
||||
{i1=9223372036854775806, i2=100000} {i1+i2} 9.22337203685488e+18
|
||||
test_expr expr-1.203\
|
||||
{i1=9223372036854775807, i2=0} {i1+i2} 9223372036854775807
|
||||
test_expr expr-1.204\
|
||||
{i1=9223372036854775807, i2=1} {i1+i2} 9.22337203685478e+18
|
||||
test_expr expr-1.205\
|
||||
{i2=9223372036854775806, i1=1} {i1+i2} 9223372036854775807
|
||||
test_expr expr-1.206\
|
||||
{i2=9223372036854775806, i1=2} {i1+i2} 9.22337203685478e+18
|
||||
test_expr expr-1.207\
|
||||
{i2=9223372036854775806, i1=100000} {i1+i2} 9.22337203685488e+18
|
||||
test_expr expr-1.208\
|
||||
{i2=9223372036854775807, i1=0} {i1+i2} 9223372036854775807
|
||||
test_expr expr-1.209\
|
||||
{i2=9223372036854775807, i1=1} {i1+i2} 9.22337203685478e+18
|
||||
test_expr expr-1.210\
|
||||
{i1=-9223372036854775807, i2=-1} {i1+i2} -9223372036854775808
|
||||
test_expr expr-1.211\
|
||||
{i1=-9223372036854775807, i2=-2} {i1+i2} -9.22337203685478e+18
|
||||
test_expr expr-1.212\
|
||||
{i1=-9223372036854775807, i2=-100000} {i1+i2} -9.22337203685488e+18
|
||||
test_expr expr-1.213\
|
||||
{i1=-9223372036854775808, i2=0} {i1+i2} -9223372036854775808
|
||||
test_expr expr-1.214\
|
||||
{i1=-9223372036854775808, i2=-1} {i1+i2} -9.22337203685478e+18
|
||||
test_expr expr-1.215\
|
||||
{i2=-9223372036854775807, i1=-1} {i1+i2} -9223372036854775808
|
||||
test_expr expr-1.216\
|
||||
{i2=-9223372036854775807, i1=-2} {i1+i2} -9.22337203685478e+18
|
||||
test_expr expr-1.217\
|
||||
{i2=-9223372036854775807, i1=-100000} {i1+i2} -9.22337203685488e+18
|
||||
test_expr expr-1.218\
|
||||
{i2=-9223372036854775808, i1=0} {i1+i2} -9223372036854775808
|
||||
test_expr expr-1.219\
|
||||
{i2=-9223372036854775808, i1=-1} {i1+i2} -9.22337203685478e+18
|
||||
test_expr expr-1.220\
|
||||
{i1=9223372036854775806, i2=-1} {i1-i2} 9223372036854775807
|
||||
test_expr expr-1.221\
|
||||
{i1=9223372036854775806, i2=-2} {i1-i2} 9.22337203685478e+18
|
||||
test_expr expr-1.222\
|
||||
{i1=9223372036854775806, i2=-100000} {i1-i2} 9.22337203685488e+18
|
||||
test_expr expr-1.223\
|
||||
{i1=9223372036854775807, i2=0} {i1-i2} 9223372036854775807
|
||||
test_expr expr-1.224\
|
||||
{i1=9223372036854775807, i2=-1} {i1-i2} 9.22337203685478e+18
|
||||
test_expr expr-1.225\
|
||||
{i2=-9223372036854775806, i1=1} {i1-i2} 9223372036854775807
|
||||
test_expr expr-1.226\
|
||||
{i2=-9223372036854775806, i1=2} {i1-i2} 9.22337203685478e+18
|
||||
test_expr expr-1.227\
|
||||
{i2=-9223372036854775806, i1=100000} {i1-i2} 9.22337203685488e+18
|
||||
test_expr expr-1.228\
|
||||
{i2=-9223372036854775807, i1=0} {i1-i2} 9223372036854775807
|
||||
test_expr expr-1.229\
|
||||
{i2=-9223372036854775807, i1=1} {i1-i2} 9.22337203685478e+18
|
||||
test_expr expr-1.230\
|
||||
{i1=-9223372036854775807, i2=1} {i1-i2} -9223372036854775808
|
||||
test_expr expr-1.231\
|
||||
{i1=-9223372036854775807, i2=2} {i1-i2} -9.22337203685478e+18
|
||||
test_expr expr-1.232\
|
||||
{i1=-9223372036854775807, i2=100000} {i1-i2} -9.22337203685488e+18
|
||||
test_expr expr-1.233\
|
||||
{i1=-9223372036854775808, i2=0} {i1-i2} -9223372036854775808
|
||||
test_expr expr-1.234\
|
||||
{i1=-9223372036854775808, i2=1} {i1-i2} -9.22337203685478e+18
|
||||
test_expr expr-1.235\
|
||||
{i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808
|
||||
test_expr expr-1.236\
|
||||
{i2=9223372036854775807, i1=-2} {i1-i2} -9.22337203685478e+18
|
||||
test_expr expr-1.237\
|
||||
{i2=9223372036854775807, i1=-100000} {i1-i2} -9.22337203685488e+18
|
||||
test_expr expr-1.238\
|
||||
{i2=9223372036854775807, i1=0} {i1-i2} -9223372036854775807
|
||||
test_expr expr-1.239\
|
||||
{i2=9223372036854775807, i1=-1} {i1-i2} -9223372036854775808
|
||||
|
||||
test_expr expr-1.250\
|
||||
{i1=4294967296, i2=2147483648} {i1*i2} 9.22337203685478e+18
|
||||
test_expr expr-1.251\
|
||||
{i1=4294967296, i2=2147483647} {i1*i2} 9223372032559808512
|
||||
test_expr expr-1.252\
|
||||
{i1=-4294967296, i2=2147483648} {i1*i2} -9223372036854775808
|
||||
test_expr expr-1.253\
|
||||
{i1=-4294967296, i2=2147483647} {i1*i2} -9223372032559808512
|
||||
test_expr expr-1.254\
|
||||
{i1=4294967296, i2=-2147483648} {i1*i2} -9223372036854775808
|
||||
test_expr expr-1.255\
|
||||
{i1=4294967296, i2=-2147483647} {i1*i2} -9223372032559808512
|
||||
test_expr expr-1.256\
|
||||
{i1=-4294967296, i2=-2147483648} {i1*i2} 9.22337203685478e+18
|
||||
test_expr expr-1.257\
|
||||
{i1=-4294967296, i2=-2147483647} {i1*i2} 9223372032559808512
|
||||
|
||||
}}
|
||||
|
||||
ifcapable floatingpoint {
|
||||
test_expr expr-2.1 {r1=1.23, r2=2.34} {r1+r2} 3.57
|
||||
test_expr expr-2.2 {r1=1.23, r2=2.34} {r1-r2} -1.11
|
||||
|
@@ -354,7 +354,7 @@ do_test index-11.1 {
|
||||
}
|
||||
set sqlite_search_count 0
|
||||
concat [execsql {SELECT c FROM t3 WHERE b==10}] $sqlite_search_count
|
||||
} {0.1 3}
|
||||
} {0.1 2}
|
||||
integrity_check index-11.2
|
||||
|
||||
|
||||
|
66
test/mem5.test
Normal file
66
test/mem5.test
Normal file
@@ -0,0 +1,66 @@
|
||||
# 2011 March 9
|
||||
#
|
||||
# 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 contains tests of the mem5 allocation subsystem.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !mem5 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# The tests in this file configure the lookaside allocator after a
|
||||
# connection is opened. This will not work if there is any "presql"
|
||||
# configured (SQL run within the [sqlite3] wrapper in tester.tcl).
|
||||
if {[info exists ::G(perm:presql)]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
do_test mem5-1.1 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap 25000000 0
|
||||
sqlite3_config_lookaside 0 0
|
||||
sqlite3_initialize
|
||||
} {SQLITE_OK}
|
||||
|
||||
# try with min request size = 2^30
|
||||
do_test mem5-1.2 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap 1 1073741824
|
||||
sqlite3_config_lookaside 0 0
|
||||
sqlite3_initialize
|
||||
} {SQLITE_NOMEM}
|
||||
|
||||
# try with min request size = 2^30+1
|
||||
# previously this was causing the memsys5Log() func to infinitely loop.
|
||||
do_test mem5-1.3 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap 1 1073741825
|
||||
sqlite3_config_lookaside 0 0
|
||||
sqlite3_initialize
|
||||
} {SQLITE_NOMEM}
|
||||
|
||||
do_test mem5-1.4 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap 0 0
|
||||
sqlite3_config_lookaside 0 0
|
||||
sqlite3_initialize
|
||||
} {SQLITE_OK}
|
||||
|
||||
finish_test
|
170
test/omitunique.test
Normal file
170
test/omitunique.test
Normal file
@@ -0,0 +1,170 @@
|
||||
# 2011 March 10
|
||||
#
|
||||
# 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. The
|
||||
# focus of this file is testing the SQLITE_OMIT_UNIQUE_ENFORCEMENT
|
||||
# compiler option.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
set uniq_enforced 1
|
||||
ifcapable !unique_enforcement {
|
||||
set uniq_enforced 0
|
||||
}
|
||||
|
||||
# table with UNIQUE keyword on column
|
||||
do_test omitunique-1.1 {
|
||||
catchsql { CREATE TABLE t1(a TEXT UNIQUE); }
|
||||
} {0 {}}
|
||||
|
||||
# table with UNIQUE clause on column
|
||||
do_test omitunique-1.2 {
|
||||
catchsql { CREATE TABLE t2(a TEXT, UNIQUE(a)); }
|
||||
} {0 {}}
|
||||
|
||||
# table with UNIQUE index on column
|
||||
do_test omitunique-1.3 {
|
||||
catchsql {
|
||||
CREATE TABLE t3(a TEXT);
|
||||
CREATE UNIQUE INDEX t3a ON t3(a);
|
||||
}
|
||||
} {0 {}}
|
||||
|
||||
# table with regular index on column
|
||||
do_test omitunique-1.4 {
|
||||
catchsql {
|
||||
CREATE TABLE t4(a TEXT);
|
||||
CREATE INDEX t4a ON t4(a);
|
||||
}
|
||||
} {0 {}}
|
||||
|
||||
# table with no index on column
|
||||
do_test omitunique-1.5 {
|
||||
catchsql { CREATE TABLE t5(a TEXT); }
|
||||
} {0 {}}
|
||||
|
||||
# run our tests using several table/index forms
|
||||
foreach {j tbl uniq cnt qp_est stat_enforce stat_omit } {
|
||||
1 {t1} 1 1 1 {2 1} {9 9}
|
||||
2 {t2} 1 1 1 {2 1} {9 9}
|
||||
3 {t3} 1 1 1 {2 1} {9 9}
|
||||
4 {t4} 0 9 10 {9 9} {9 9}
|
||||
5 {t5} 0 9 100000 9 9
|
||||
} {
|
||||
|
||||
do_test omitunique-2.0.$j.1 {
|
||||
catchsql [ subst {INSERT INTO $tbl (a) VALUES('abc'); }]
|
||||
} {0 {}}
|
||||
do_test omitunique-2.0.$j.2 {
|
||||
catchsql [ subst {INSERT INTO $tbl (a) VALUES('123'); }]
|
||||
} {0 {}}
|
||||
|
||||
# check various INSERT commands
|
||||
foreach {i cmd err} {
|
||||
1 {INSERT} 1
|
||||
2 {INSERT OR IGNORE} 0
|
||||
3 {INSERT OR REPLACE} 0
|
||||
4 {REPLACE} 0
|
||||
5 {INSERT OR FAIL} 1
|
||||
6 {INSERT OR ABORT} 1
|
||||
7 {INSERT OR ROLLBACK} 1
|
||||
} {
|
||||
|
||||
ifcapable explain {
|
||||
set x [execsql [ subst { EXPLAIN $cmd INTO $tbl (a) VALUES('abc'); }]]
|
||||
ifcapable unique_enforcement {
|
||||
do_test omitunique-2.1.$j.$i.1 {
|
||||
regexp { IsUnique } $x
|
||||
} $uniq
|
||||
}
|
||||
ifcapable !unique_enforcement {
|
||||
do_test omitunique-2.1.$j.$i.1 {
|
||||
regexp { IsUnique } $x
|
||||
} {0}
|
||||
}
|
||||
}
|
||||
|
||||
if { $uniq_enforced==0 || $uniq==0 || $err==0 } {
|
||||
set msg {0 {}}
|
||||
} {
|
||||
set msg {1 {column a is not unique}}
|
||||
}
|
||||
do_test omitunique-2.1.$j.$i.3 {
|
||||
catchsql [ subst {$cmd INTO $tbl (a) VALUES('abc'); }]
|
||||
} $msg
|
||||
|
||||
}
|
||||
# end foreach cmd
|
||||
|
||||
# check UPDATE command
|
||||
ifcapable explain {
|
||||
set x [execsql [ subst { EXPLAIN UPDATE $tbl SET a='abc'; }]]
|
||||
ifcapable unique_enforcement {
|
||||
do_test omitunique-2.2.$j.1 {
|
||||
regexp { IsUnique } $x
|
||||
} $uniq
|
||||
}
|
||||
ifcapable !unique_enforcement {
|
||||
do_test omitunique-2.2.$j.1 {
|
||||
regexp { IsUnique } $x
|
||||
} {0}
|
||||
}
|
||||
}
|
||||
if { $uniq_enforced==0 || $uniq==0 } {
|
||||
set msg {0 {}}
|
||||
} {
|
||||
set msg {1 {column a is not unique}}
|
||||
}
|
||||
do_test omitunique-2.2.$j.3 {
|
||||
catchsql [ subst { UPDATE $tbl SET a='abc'; }]
|
||||
} $msg
|
||||
|
||||
# check record counts
|
||||
do_test omitunique-2.3.$j {
|
||||
execsql [ subst { SELECT count(*) FROM $tbl WHERE a='abc'; }]
|
||||
} $cnt
|
||||
|
||||
# make sure the query planner row estimate not affected because of omit enforcement
|
||||
ifcapable explain {
|
||||
do_test omitunique-2.4.$j {
|
||||
set x [ execsql [ subst { EXPLAIN QUERY PLAN SELECT count(*) FROM $tbl WHERE a='abc'; }]]
|
||||
set y [ subst {~$qp_est row} ]
|
||||
regexp $y $x
|
||||
} {1}
|
||||
}
|
||||
|
||||
# make sure we omit extra OP_Next opcodes when the UNIQUE constraints
|
||||
# mean there will only be a single pass through the code
|
||||
ifcapable explain {
|
||||
set x [execsql [ subst { EXPLAIN SELECT * FROM $tbl WHERE a='abc'; }]]
|
||||
do_test omitunique-2.5.$j {
|
||||
if { [ regexp { Next } $x ] } { expr { 0 } } { expr { 1 } }
|
||||
} $uniq
|
||||
}
|
||||
|
||||
# make sure analyze index stats correct
|
||||
ifcapable analyze {
|
||||
if { $uniq_enforced==0 } {
|
||||
set msg [ list $stat_omit ]
|
||||
} {
|
||||
set msg [ list $stat_enforce ]
|
||||
}
|
||||
do_test omitunique-2.6.$j {
|
||||
execsql [ subst { ANALYZE $tbl; } ]
|
||||
execsql [ subst { SELECT stat FROM sqlite_stat1 WHERE tbl='$tbl'; } ]
|
||||
} $msg
|
||||
}
|
||||
|
||||
}
|
||||
# end foreach tbl
|
||||
|
||||
finish_test
|
@@ -56,7 +56,7 @@ do_test 1.1.2 {
|
||||
catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
|
||||
} {1}
|
||||
|
||||
do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
|
||||
do_re_test 1.1.3 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) open\(.*test.db\) - }
|
||||
|
||||
|
||||
# Test a failure in open() due to the path being a directory.
|
||||
@@ -67,7 +67,7 @@ do_test 1.2.1 {
|
||||
list [catch { sqlite3 dbh dir.db } msg] $msg
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c: open.*dir.db$}
|
||||
do_re_test 1.2.2 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) open\(.*dir.db\) - }
|
||||
|
||||
# Test a failure in open() due to the path not existing.
|
||||
#
|
||||
@@ -76,7 +76,7 @@ do_test 1.3.1 {
|
||||
list [catch { sqlite3 dbh /x/y/z/test.db } msg] $msg
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
|
||||
do_re_test 1.3.2 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) open\(.*test.db\) - }
|
||||
|
||||
# Test a failure in open() due to the path not existing.
|
||||
#
|
||||
@@ -85,7 +85,7 @@ do_test 1.4.1 {
|
||||
list [catch { sqlite3 dbh /root/test.db } msg] $msg
|
||||
} {1 {unable to open database file}}
|
||||
|
||||
do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c: open.*test.db$}
|
||||
do_re_test 1.4.2 { lindex $::log 0 } {^os_unix.c:\d*: \(\d+\) open\(.*test.db\) - }
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# Tests oserror-1.* test failures in the unlink() system call.
|
||||
@@ -98,7 +98,7 @@ do_test 2.1.1 {
|
||||
catchsql { SELECT * FROM sqlite_master } dbh
|
||||
} {1 {disk I/O error}}
|
||||
|
||||
do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c: unlink.*test.db-wal$}
|
||||
do_re_test 2.1.2 { lindex $::log 0 } {^os_unix.c:\d+: \(\d+\) unlink\(.*test.db-wal\) - }
|
||||
do_test 2.1.3 {
|
||||
dbh close
|
||||
forcedelete test.db-wal
|
||||
@@ -109,4 +109,3 @@ sqlite3_shutdown
|
||||
test_sqlite3_log
|
||||
sqlite3_initialize
|
||||
finish_test
|
||||
|
||||
|
0
test/progress.test
Executable file → Normal file
0
test/progress.test
Executable file → Normal file
0
tool/mkopts.tcl
Executable file → Normal file
0
tool/mkopts.tcl
Executable file → Normal file
@@ -202,6 +202,7 @@ proc main {argv} {
|
||||
SQLITE_OMIT_TRACE \
|
||||
SQLITE_OMIT_TRIGGER \
|
||||
SQLITE_OMIT_TRUNCATE_OPTIMIZATION \
|
||||
SQLITE_OMIT_UNIQUE_ENFORCEMENT \
|
||||
SQLITE_OMIT_UTF16 \
|
||||
SQLITE_OMIT_VACUUM \
|
||||
SQLITE_OMIT_VIEW \
|
||||
|
Reference in New Issue
Block a user