Compare commits

..

281 Commits

Author SHA1 Message Date
drh a925fd256b Change the xShmSize() implementation in os_unix.c so that it will only
increase and never decrease the size of a shared-memory segment.

FossilOrigin-Name: 149d2ae4a6fe2f86822f286d2a7092c51bec7ebb
2010-05-13 08:33:35 +00:00
dan bd50ddeb42 Fix for a segfault that can follow a malloc failure.
FossilOrigin-Name: 3cab9022457ce50f82c5822d8ba6c04a3a85cb6a
2010-05-13 07:08:53 +00:00
dan 7fd555a634 Modify the VFS in test_vfs.c to match the refactoring of the xShmXXX methods.
FossilOrigin-Name: 25e72f81561575051c63e9bf5d2c8e76f9fcf5c6
2010-05-13 06:19:37 +00:00
drh 365e2d255b Fix for the test_devsym.c test module for the VFS-SHM refactoring.
FossilOrigin-Name: 49d62933759d4e160ee3a4dd2aa316a2f5bbb4e6
2010-05-12 18:30:36 +00:00
drh 686138fe88 A couple simple fixes to get wal.test mostly working.
FossilOrigin-Name: c74458127468f30b16715594c8d68e9d3c05d292
2010-05-12 18:10:52 +00:00
drh d9e5c4f6ed Refactoring the VFS-SHM methods used by WAL. This version compiles and
runs non-WAL test cases but crashes and burns on wal.test.

FossilOrigin-Name: 2b00152c1ac0b3735aa6cfab61259ff04d81c701
2010-05-12 18:01:39 +00:00
drh eaf52d883a Remove the OP_Variable optimization of check-in [48b77b04935d894] since it
can lead to malfunctions as described in ticket [26ff0c82d1e90].

FossilOrigin-Name: 7838163d087780a6fb403a17641b96f71baec088
2010-05-12 13:50:23 +00:00
dan ed36020daf Remove a branch made redundant by the earlier exclusive-mode changes.
FossilOrigin-Name: c501b2ede6aad123bef0aa7ce8b356a134eb6d26
2010-05-12 06:54:31 +00:00
dan 97c1f6c8f2 Have os_unix.c use the suffix "-wal-index" for wal-index files instead of "-wal-inde".
FossilOrigin-Name: 885e854e7cdc79ecc9d5772d563ddc0f61753ab6
2010-05-11 16:29:54 +00:00
drh be5481578a When an attempt to change journal_mode fails due to locks, be sure to
leave internal structures in a consistent state.

FossilOrigin-Name: cf3d1e0b8a739302cf2848ac3e6eaaae04e6a44c
2010-05-11 14:00:39 +00:00
dan 5543759b1b Changes so that WAL and exclusive-locking mode work together.
FossilOrigin-Name: 71e7b1cf9f4cd02a2a9bc8a3e58acd7a7e3c7e60
2010-05-11 12:19:26 +00:00
shaneh a10069dd22 Updates for to WAL TCL test scripts to support running on Windows.
FossilOrigin-Name: 6a5630806c87b0f4e5632c37c357f98effd9608a
2010-05-11 02:46:16 +00:00
drh 09b1330026 Fix an off-by-one error while constructing the name of the mmap file for
the wal-index under os_unix.c.

FossilOrigin-Name: 6e3735f72cb7d2f4d16c8f9bc59ff159c75243e5
2010-05-10 19:51:32 +00:00
dan 7ddccd2aad Merge [96d6eaf4d2] and [40b0a6357b].
FossilOrigin-Name: c67756c404669141fa06a1ce3f1efadefa277bc6
2010-05-10 18:10:17 +00:00
drh 1c5bb4d69c Fix an uninitialized variable in OSX proxy locking.
FossilOrigin-Name: 96d6eaf4d2be453191b36875811d9556ad0763ed
2010-05-10 17:29:28 +00:00
dan bb23aff3df Modify the format of the wal-index to use a hash table to index log file segments.
FossilOrigin-Name: 40b0a6357b160e04326ab176955a68a1cf3f8b7c
2010-05-10 14:46:09 +00:00
drh acd0781892 If an ATTACH command files due to OP_JournalMode but still attaches the
database, make sure VACUUM still detaches it when done.

FossilOrigin-Name: 6ecdc7ba2b5e79e8b5862fb49cf6c2b99a40659a
2010-05-10 14:10:57 +00:00
drh ab9b74443c Enhance the OP_JournalMode opcode with an ignore-errors option and use that
option the ATTACH command.

FossilOrigin-Name: 0bdea4cfbd7832f2a00c01b93c92ba13d20139ef
2010-05-10 11:20:05 +00:00
drh 2905f053ef When running a checkpoint while in locking_mode=EXCLUSIVE, be sure to move
the wal-index lock to UNLOCK from READ prior to promoting to CHECKPOINT.

FossilOrigin-Name: be114bdf9bb98c7287f8cb54340c630b0c412e9d
2010-05-07 20:34:17 +00:00
drh e874d9ed79 Change the xShmOpen() method of the VFS to take the database file name as
its argument, not the WAL file name.  Also fix some unrelated compiler
warnings.

FossilOrigin-Name: a65c2939267ef6acec4e355a207f98f217e263d6
2010-05-07 20:02:23 +00:00
drh 6a2607a131 Additional tweaks to API documentation. No functional code changes.
FossilOrigin-Name: e1230782a371f09cd46dacc8ecbc6a0c5baab2d5
2010-05-07 18:23:24 +00:00
drh 005e19c4c1 Updates to documentation on the C interfaces supporting WAL. No functional
changes to code.

FossilOrigin-Name: 681ba20cf077e9a0fccd51ed50101ad0f2c67eb3
2010-05-07 13:57:11 +00:00
dan c6315a44b2 Fix a recently introduced problem in wal.test.
FossilOrigin-Name: 79b52d0ff7a7b717bde55b97ff05ad17418bc7d7
2010-05-07 13:52:42 +00:00
dan 65bddc1223 Change wal.test and walhook.test so that they work with DEFAULT_AUTOVACUUM=1 builds.
FossilOrigin-Name: 4cde92909c20982f7d4e6b550f55d786df398ccd
2010-05-07 12:49:22 +00:00
dan 65f2ac58b6 Test another IO error case in wal.c.
FossilOrigin-Name: 8b3b5ab8fa61ca4ef22c98abaab397707ee74ea3
2010-05-07 09:43:50 +00:00
dan 998ad21271 Fix a problem with checkpointing large log files created by an external process.
FossilOrigin-Name: 8f94bde568be52ecc5a976b7a09776ea7b4bb511
2010-05-07 06:59:08 +00:00
dan 846705021d Since walIndexTryHdr() can no longer encounter any error conditions, change tehe function signature so that it does not return an error code. This removes unreachable branches from other code.
FossilOrigin-Name: 061a282cc0bf76541ab1f99b351a49d489ff93ec
2010-05-07 05:46:23 +00:00
drh 2c47d194a2 Another attempt to fix permutations.test so that it excludes WAL tests
from the journaltest permutation.

FossilOrigin-Name: 58c404429c5af167a82899fc4c736ed7489ed746
2010-05-07 00:28:41 +00:00
drh 6763e3550d Remove savepoint6.test from the set of tests run by journaltest since
savepoint6.test uses journal_mode=WAL.

FossilOrigin-Name: 811b45a96bfaa0ef2394b86c06e8f099a07ee9f0
2010-05-06 22:21:14 +00:00
drh 3ebaee9633 The PRAGMA journal_mode=WAL; command now makes WAL the default journal mode
for new databases added with ATTACH, so the behavior is consistent with the
other journal modes.

FossilOrigin-Name: c3520460a4a39fc5e981c3033068ffbb422a4af2
2010-05-06 21:37:22 +00:00
drh 72af0774f9 Make sure to do a clean shutdown of the library upon existing the shell
in order to remove WAL files.

FossilOrigin-Name: c1762dda00b8bdb7c3247617ac4cb654f1d95cf7
2010-05-06 20:19:55 +00:00
drh fb4a626da0 Exclude all WAL tests from the journaltest permutation.
FossilOrigin-Name: 46c97d7eee9359cd21139a6520633f5d16594ab0
2010-05-06 19:55:57 +00:00
shaneh fd06863881 Changes to support SQLITE_OMIT_WAL.
FossilOrigin-Name: 32a8501d78714cc390eba5f993f329ef3b499878
2010-05-06 19:20:29 +00:00
drh 08fba00781 Updates to the VFS SHM locking documentation.
FossilOrigin-Name: 9927ce421090ac20285cf05768b38e1f91826a68
2010-05-06 19:04:48 +00:00
dan 65be0d8cce Instead of transitioning to RECOVER state from CHECKPOINT when a recovery is required, perform the recovery while holding the CHECKPOINT lock.
FossilOrigin-Name: bb0b6021e721c2e4f1533ab18381604c6b7b31d5
2010-05-06 18:48:27 +00:00
dan 5273f58f37 If recovery is run before a checkpoint, change back to a CHECKPOINT lock before performing the actual checkpoint.
FossilOrigin-Name: dc98ee169cfa43c89f1b36fb1150d4788710fda3
2010-05-06 18:27:19 +00:00
dan 576bc3294d Only pass -1 as the size parameter to xShmGet when the caller does not care what size mapping is returned. Only call xShmSize when the underlying allocation (not the mapping) should be resized.
FossilOrigin-Name: 637f51ddf9e4a57e1f171b6d2c6c93152074267e
2010-05-06 18:04:50 +00:00
dan b7d53f54ae Fix a bug whereby an old snapshot could be checkpointed (and subsequent transactions discarded) if the last connection to disconnect from a WAL database happended to be holding an out-of-date wal-index header.
FossilOrigin-Name: d0c0034b0baa83046c1d6b94c886f7039e4e06f5
2010-05-06 17:28:08 +00:00
drh 6e5b37faef After throwing an error to say that one cannot change into WAL mode within
a tranactions, do not then go and change into WAL mode.

FossilOrigin-Name: 56a17dae91600a3863903f8d654ed52a0f720caf
2010-05-06 16:06:38 +00:00
dan d41a29a653 Further coverage tests.
FossilOrigin-Name: 98a9713e0030a36ea99a18a12a2e7685c6db72b3
2010-05-06 15:56:28 +00:00
shaneh 84aab39782 Update configure scripts for WAL support.
FossilOrigin-Name: 2edc5129f216abec9b13a0ad9b6640606caa9f72
2010-05-06 15:35:59 +00:00
dan a861469a07 Add tests to cover a couple of branches in wal.c.
FossilOrigin-Name: 429f437fb776fc974a6adf791b729e25bea82fef
2010-05-06 14:42:34 +00:00
dan c9e4665e7d Unset a tcl variable before reusing it in wal.test.
FossilOrigin-Name: e83efb232fe8d30714f4c7cffeef80092aea4df7
2010-05-06 13:36:47 +00:00
dan ff6dfc73fe Add tests for some lock-contention cases.
FossilOrigin-Name: f0fcb9c9a67e2bf7bbedbedbc27791b605a21dd1
2010-05-06 12:15:48 +00:00
drh e404de05c0 Remove the noop-mutex implementations of mutex_held() and mutex_notheld()
since they are both unreachable.

FossilOrigin-Name: 6767b62a9a063582889f5ceb42f95eab24c697da
2010-05-06 11:56:52 +00:00
drh 24e3971197 Add two text files containing pager design notes to the doc/ subfolder.
FossilOrigin-Name: ed817fc893e7162ae0ff4022591f7e9e3b81d622
2010-05-06 11:55:56 +00:00
dan 9a6b4e9adb Add test cases to test the libraries handling of corrupt wal-index headers.
FossilOrigin-Name: 9465b267d420120c050bbe4f143ac824146a9e4a
2010-05-06 11:32:09 +00:00
dan 8f6097c244 Add tests for handling errors returned by xShm VFS methods.
FossilOrigin-Name: fbbcacb137e8f5246b88ad09331236aaa1900f60
2010-05-06 07:43:58 +00:00
drh 5def0843f1 Change the behavior of the sqlite3_wal_hook() callback. It should now return
SQLITE_OK or an error code and the error code is propagated back up the 
stack.  If a checkpoint is desired, the callback should invoke
sqlite3_wal_callback() itself.

FossilOrigin-Name: 1b14195e05fe5551992a39246ec3bcf6a33bbfac
2010-05-05 20:00:25 +00:00
drh ccd13d1f80 Further simplifications to the SHM locking logic. Remove the SQLITE_SHM_QUERY
option.  Unify the WRITE to READ and RECOVER to READ transitions.

FossilOrigin-Name: e9bfa6e4ce7d1edc6be8b9173ac3b6bfd180632a
2010-05-05 19:09:49 +00:00
dan c7991bdf29 Test the handling of errors returned by the xShmXXX() APIs.
FossilOrigin-Name: 72663123d6be2b194cad7a6057d0f20dd0d9fe05
2010-05-05 19:04:59 +00:00
drh 5c10f77d52 Do not compare page sizes on source and destination of backup until
transactions are started and the page sizes are locked.  This is a
fix to check-in [7bd44794c4].

FossilOrigin-Name: ec7157788b16936b4b6e4642107b3c86aa44df24
2010-05-05 18:46:44 +00:00
drh 4bc79def36 Simplifications to the SHM locking implementation in os_unix.c.
FossilOrigin-Name: 9de05bfb09e29bafdf5782263330fe8eefcfaba3
2010-05-05 18:20:07 +00:00
drh 3289c5efc8 Prohibit backup if the destination is using WAL and has a different page
size from the source.

FossilOrigin-Name: 7bd44794c482beee16c684712545275e2bf63dfa
2010-05-05 16:23:26 +00:00
dan 1018e90b1e When closing a WAL database, if the exclusive lock on the database file is obtained and the database successfully checkpointed, delete the wal-index file from the file system.
FossilOrigin-Name: 2ac5d96c8e5831b392d83c86491d9ed8bc9c8db7
2010-05-05 15:33:05 +00:00
drh 16adb77623 Make sure the page size of the main database is fixed following a
failed VACUUM attempt.  Otherwise, two consecutive failed VACUUM attempts
with attempted page_size changes on encrypted or WAL databases could
result in database corruption.

FossilOrigin-Name: 208e7d5d3a8915433dbf50c6cc6698ec6c8df944
2010-05-05 04:11:44 +00:00
drh 811bdbd206 Do not attempt to modify the page_size when running VACUUM on a WAL database.
FossilOrigin-Name: 58a1a59be89b33c6d5fa8b43571037d7d96625a1
2010-05-05 03:39:53 +00:00
drh fc34ad291e Get the previous mutex fix working with SQLITE_DEBUG and with the amalgamation.
FossilOrigin-Name: df19928f7ee94bca3989313ff16507c15d6efe2b
2010-05-05 00:22:21 +00:00
drh 92d7652379 When the in single-threaded mode, the sqlite3_mutex_alloc() interface
still returns a non-NULL value.  The mutex doesn't do anything, but it
tests non-NULL.  This way, extensions (or VFSes) that use sqlite3_mutex_alloc()
can tell the difference between an OOM error and mutexes being disabled.

FossilOrigin-Name: 451fd175758983c335aab449fdc4cb838156c4cb
2010-05-05 00:05:24 +00:00
drh 7721b23e0a When sqlite3PagerPagecount() is called without any locks, always return
the physical file size, not the logical file size.

FossilOrigin-Name: 4016b422286587beda7323052d27821adb1fed73
2010-05-04 18:50:40 +00:00
drh a8e654eb38 Be sure to release all wal-index locks before closing the wal-index.
FossilOrigin-Name: b15b67fa14ff77963f470678ff6188c63be8e079
2010-05-04 17:38:42 +00:00
drh cd058ec4ef Relax an over-zealous assert() in sqlite3WalUndo().
FossilOrigin-Name: 8f9d22d58c75ad7476c1eea8ba296347e30b7beb
2010-05-04 17:20:09 +00:00
drh 33bec22fb1 Take care not to invoke the xShmClose method of the VFS with a NULL
shared memory object.

FossilOrigin-Name: 1465d3842c52aa7471f63deb47fe5b256d4e01c2
2010-05-04 16:33:37 +00:00
dan 2cee6abf8e Add a test case to verify that log files containing pages that are not a power-of-two bytes in size are handled correctly.
FossilOrigin-Name: c2bf693f933313991d85394009e79a7903037a18
2010-05-04 15:20:45 +00:00
dan b6e099a973 Fix problems with recovering wal files that use a page-size other than the default.
FossilOrigin-Name: 1a391f3c55dc9d4266552fa26d2a9839c6bafce4
2010-05-04 14:47:39 +00:00
dan ef37802545 Fix a typo in walfault.test.
FossilOrigin-Name: 232dbe8ecec16485be5c5995fdf7a0ed951c2097
2010-05-04 11:06:03 +00:00
dan 8d6ad1cc2c Test that the correct number of padding frames are appended to the log file after committing a transaction in synchronous=FULL mode.
FossilOrigin-Name: a60104aa7e38e7d9f2ff2eae02687dc9c5dd5d77
2010-05-04 10:36:20 +00:00
drh d0b2677b78 Unset some global TCL variables prior to use in test where prior tests can
have those same variables set to an array value.

FossilOrigin-Name: 49bef00e5cda600ceb964148bf745de4aff1ab62
2010-05-03 19:20:46 +00:00
drh d5e6e4004b Fix a bug in the computation of the current time for the alternative
CURRENT_TIMESTAMP functions used when SQLITE_OMIT_DATETIME is defined.

FossilOrigin-Name: e7ded46b5efabe521008d9043dd72bd1ca748316
2010-05-03 19:17:01 +00:00
drh 324e46d424 Documentation stubs for sqlite3_wal_autocheckpoint and sqlite3_wal_checkpoint.
FossilOrigin-Name: 313762427d96954667909887a797ea996dc6304a
2010-05-03 18:51:41 +00:00
drh 0dcb0a7d7b Fix a bug in the xCurrentTime() method of the os_unix.c VFS.
FossilOrigin-Name: 551df11a5613e3edc6c5de44f0ac6abc2d0e6cdf
2010-05-03 18:22:52 +00:00
dan 5e9e482fe0 Add a test to simulate an OOM during log recovery to walfault.test.
FossilOrigin-Name: 7ed85e87dd206083310ba28afab4389885f61dac
2010-05-03 18:01:21 +00:00
drh 529b18706d Clear global variable "seconds" before use in walthread.test.
FossilOrigin-Name: a35551a5305b5160b0eb511da7f8e6fb351ef271
2010-05-03 17:24:45 +00:00
dan 76ed3bc044 Fix a couple of errors in WAL code that can occur in an OOM situation.
FossilOrigin-Name: 9d3f3736be42ef8ab48b099d4712e08dfca97873
2010-05-03 17:18:24 +00:00
drh 4c846bb148 Update the crash-test VFS in test6.c to pass-through the shared-memory
methods to the real underlying VFS.  This fixes the walcrash.test script.

FossilOrigin-Name: ea09ff37911376505e8262ee9841224995b696f2
2010-05-03 16:36:55 +00:00
drh 1fbe0f2a8f Change the VFS definition so that all methods take a VFS object pointer as
their first parameter.

FossilOrigin-Name: 43b5b07f0d996d7ef7426346b1792e9ca898f487
2010-05-03 16:30:27 +00:00
dan af0cfd366a Have sqlite3_wal_checkpoint() handle a zero-length string in the same way as a NULL pointer. Fix "PRAGMA wal_checkpoint" so that it checkpoints all attached databases.
FossilOrigin-Name: 7fecd21f45b9ce773ffbcef6c84066474e8cd01c
2010-05-03 15:58:50 +00:00
drh b7e8ea2015 Use VFS method xCurrentTimeInt64 instead of xCurrentTime when it is available.
Provide an implementation of xCurrentTimeInt64 for os_unix.c.

FossilOrigin-Name: ab77b3ae6da3370d8bc3b2c9c0edc723b69f5a95
2010-05-03 14:32:30 +00:00
drh e8e1c9d50e Merge the write-ahead-logging changes into the trunk.
FossilOrigin-Name: de9ae443cc8eebfb0692dcdac93bde9e4c54199a
2010-05-03 14:08:27 +00:00
dan 6fcff07f6a If the sqlite3_wal_checkpoint() API is passed a NULL pointer in place of a database name, attempt to checkpoint all attached databases.
FossilOrigin-Name: 27a5c09ce8a35039d844d08cfe5698e8b438abfe
2010-05-03 14:05:43 +00:00
drh b033d8b9dc Make sure the mutex is held while calling sqlite3ApiExit() in
sqlite3_wal_checkpoint().  Other cleanup of WAL logic.

FossilOrigin-Name: 11a85b821abff1ecb7ec8c37bc7783be9fc4ea6d
2010-05-03 13:37:30 +00:00
dan 87c1fe1b69 Have sqlite3_wal_checkpoint() populate the database handle error message and error code (as returned by sqlite3_errmsg() and sqlite3_errcode()).
FossilOrigin-Name: ff234cf574c7ae384ab1ebc79b2171ef0541bc91
2010-05-03 12:14:15 +00:00
dan 5a299f9134 Add the "PRAGMA wal_autocheckpoint" command. Rename "PRAGMA checkpoint" to "PRAGMA wal_checkpoint".
FossilOrigin-Name: 714e5947264571386f966aa8fcdd5607b5832238
2010-05-03 11:05:08 +00:00
dan 11398e5e54 Merge two wal leaves.
FossilOrigin-Name: 23c0e6c3f333e878fe5a2ae5d61df0d765f437b4
2010-05-03 08:19:34 +00:00
dan 586b9c8a94 Add the sqlite3_wal_checkpoint() and sqlite3_wal_autocheckpoint() APIs.
FossilOrigin-Name: 9803196dec85e3aa4105cc477e9cfe98d370e486
2010-05-03 08:04:49 +00:00
drh 2d536e187f Change the SHM interface so that it does not take the name of the shared
object but rather the name of the WAL file and derives its own name from
that.  Remove the xShmDelete method from the VFS and replace it with a
delete flag on xShmClose.

FossilOrigin-Name: 94dea5f9c11a68564220cec76ac3fae2ba90e907
2010-05-01 20:17:30 +00:00
drh f72a8751c9 Remove the xShmPush and xShmPull methods from the VFS.
FossilOrigin-Name: 69e07fdbde5054593de948b76dfac157cf5d4058
2010-05-01 18:23:08 +00:00
drh bee6f4ebe2 Define an invariant to guarantee deadlock-free operation of SHM in os_unix.c
and check that invariant with assert() statements.

FossilOrigin-Name: 6af2dca75b8139134ea394c1d71aefc6523f02e9
2010-05-01 17:57:36 +00:00
drh 77b95a379c Rework mutexes on the SHM implemention for os_unix to avoid a deadlock during
WAL recovery.

FossilOrigin-Name: 1a0f69bef2c489e81a3d4b910b426972e9ed4054
2010-05-01 17:50:37 +00:00
dan 5cf53537a8 Support compile-time option SQLITE_OMIT_WAL, for building without WAL support.
FossilOrigin-Name: 9b230c43dfa112e3e1589f9775926807bd36b36e
2010-05-01 16:40:20 +00:00
drh 057f1ecddb Fix a typo in the walmode.test test script introducted yesterday.
FossilOrigin-Name: dcabc90ca588281fa7a290972ec8af6816932489
2010-05-01 11:33:13 +00:00
drh 7aba8fdef7 Fix the sqlite3_mutex_alloc() interface to return NULL (not segfault) when
operating in threadsafe mode.  (This is a general-purpose bug fix which
really ought to be ported to trunk.)

FossilOrigin-Name: 64840a3caf569959c9d5e63bdbc0cf675fda3882
2010-05-01 11:19:07 +00:00
dan bb16ff75dd Add test case demonstrating deadlock during recovery of very large log files. No fix yet.
FossilOrigin-Name: 63ea318eb19d264667909c70185b8a5cdc4454c0
2010-05-01 08:30:34 +00:00
drh d80b233850 Do not allow journal_mode=WAL if the underlying VFS does not support xShmOpen.
FossilOrigin-Name: d1fcccecdc8e9ac5d0d022914e51c545f4e1b04f
2010-05-01 00:59:37 +00:00
drh 27d52b2b19 Merge in changes from the trunk.
FossilOrigin-Name: 76bf0eee1fd4003a3f1c39922f8f059611d41dd0
2010-04-30 22:28:06 +00:00
drh be837bddad Avoid assertion faults in queries using indices with redundant columns.
Ticket [3dbdcdb14e7f41].

FossilOrigin-Name: 946e06cd2a2cc209b0786b7e9d28c0746320d646
2010-04-30 21:03:24 +00:00
drh 6dea3248ae Change the SHM VFS logic in os_unix.c so that it does not hold an exclusive
lock n the mapped memory when also holding a CHECKPOINT lock.  This
improves concurrency between readers and checkpointers.

FossilOrigin-Name: 8660cda6f8ef43bd276897ef3b5fc2376b5684dc
2010-04-30 17:47:51 +00:00
drh 1b48aa49a4 Remove some obsolete debugging parameters.
FossilOrigin-Name: a012aed498bf41a5f6f3006182b0c4c2ab0fe1bb
2010-04-30 17:28:35 +00:00
dan fe05aa144c Fix a problem with resizing the wal-index mapping after the mapping has been extended by an external process.
FossilOrigin-Name: 79d356fea6008a8adf8ebd4906571375f3cf5213
2010-04-30 17:05:23 +00:00
dan c9d53dbe5a Fix a problem with calculating the required size of the wal-index when appending frames.
FossilOrigin-Name: 9526b11130f3ed2f5227386a26263c767214603a
2010-04-30 16:50:00 +00:00
drh 400df2ea70 In the debugging output for SHM-LOCK in os_unix.c, use symbolic names
for the lock states rather than raw numbers.

FossilOrigin-Name: 2afc33de2b2012d034fb0d2057a5a45e304516ca
2010-04-30 16:48:19 +00:00
dan 43a56b812c Fix a problem in the previous commit. Both unixShm.lockState and unixShm.readLock should be set to READ when downgrading from a WRITE to a READ lock
FossilOrigin-Name: 90119fecbce06c8db82194dfd9d5045be29b1cda
2010-04-30 16:41:53 +00:00
dan 78daa5a7d9 Fix a bug whereby upgrading from a READ_FULL to a WRITE lock, and then back to a read lock was dropping all WAL locks.
FossilOrigin-Name: 55f5af5e174df7a28deeb36faa51138926669897
2010-04-30 16:38:59 +00:00
dan 30c8629e67 Reapply commits [837d82a929] and [c05e7dca17] that were accidentally overwritten.
FossilOrigin-Name: 598de52700ba13e3228289220a74fc62073c62d4
2010-04-30 16:24:46 +00:00
dan 6ddb4bf938 Add xShmXXX() methods to the test VFS in test_devsym.test.
FossilOrigin-Name: 1d20342424b452ea96aaf161de1f98f26a9155a0
2010-04-30 16:19:39 +00:00
drh 49156b2b5e Correctly record the fact that the SHM lock reached PENDING if it did so
but failed to reach CHECKPOINT.

FossilOrigin-Name: d9250e84ac1fc6590f8670e1d801630650c7846a
2010-04-30 16:12:04 +00:00
drh d749084ad0 Fix a couple uninitialized variables in the xShmLock method of the unix VFS.
Improved debugging logic for xShmLock.

FossilOrigin-Name: 69567c5fca9e30b7660e6f56350be929c3890d7e
2010-04-30 15:54:46 +00:00
dan a7ad518ef0 When closing a WAL connection, attempt an exclusive lock on the database file. If the lock is obtained, checkpoint the database and delete the wal and wal-index files.
FossilOrigin-Name: c05e7dca172719f33e245c08d0c0e8ab47e5a537
2010-04-30 15:49:27 +00:00
dan 6045461eee If a reader attempts to upgrade to a writer, but is not reading the most recent database snapshot, return SQLITE_BUSY.
FossilOrigin-Name: 837d82a92977cbfa0963411daf8160d286a7ed32
2010-04-30 15:24:43 +00:00
drh 5530b764a8 Separate the concepts of underlying storage size and mapped size in the
VFS shared-memory implementation.

FossilOrigin-Name: 4cbe49f13fed288f94ff305bcfd99df907bf7baf
2010-04-30 14:39:50 +00:00
dan 87bfb51ef8 Add a missing walIndexUnmap() call to the checkpoint code. Change a couple of SQLITE_CANTOPEN constants to SQLITE_CANTOPEN_BKPT.
FossilOrigin-Name: 1f9e8c5c27ae2c68bc01d8e2bb2c662be7b3f161
2010-04-30 11:43:28 +00:00
dan 1bc6171c23 Fix an assert() in sqlite3WalRead().
FossilOrigin-Name: 2e7a0050e192dd197d4db92393ab120897c14836
2010-04-30 10:24:54 +00:00
dan e93808dde2 Add missing mutexes to unixShmClose().
FossilOrigin-Name: a4741cb54dd5e753d48fd05ac9dbe27ee4aa1ec0
2010-04-30 10:06:09 +00:00
dan 4c97b53425 Fix a couple of assert() statements in os_unix.c and wal.c. Combine sqlite3WalIsDirty() with sqlite3WalUndo().
FossilOrigin-Name: a8f958be804ee05c4137b3cd110db344713af5f2
2010-04-30 09:52:17 +00:00
dan ba51590bcd Add a missing walIndexUnmap() to sqlite3WalSnapshotOpen().
FossilOrigin-Name: 72b95fde15dae56390dc8d4168fb2757447e289e
2010-04-30 09:32:06 +00:00
dan 5047af405b Merge latest bugfix into wal branch.
FossilOrigin-Name: 265e66e6984c32999bf93981e3b1d19887dfe599
2010-04-30 06:02:30 +00:00
drh 79e6c78ccc The first 6 WAL tests now work. It's a start.
FossilOrigin-Name: a92c1851da10acf51e7f6f086b8a23bd731940b3
2010-04-30 02:13:26 +00:00
dan 6908343c65 Zero the "immediate FK constraint counter" associated with a statement object when sqlite3_reset() is called. Fix for [c39ff61c43].
FossilOrigin-Name: f660be615a0c1f4641782a83744533f5d3119218
2010-04-29 22:57:56 +00:00
drh 7ed91f2344 Refactor wal.c to use the VFS. This check-in compiles and links and works
ok as long as you leave WAL turned off, but WAL does not work.

FossilOrigin-Name: 62db5fa3b61be885b2d94e9b9ce3877b2c588350
2010-04-29 22:34:07 +00:00
drh 31cbbbad1c Untested implementation of the shared-memory dead-man-switch.
FossilOrigin-Name: 706611283ea2575c2942543391026b36061cfc1c
2010-04-29 16:40:51 +00:00
drh 7b6944047e Progress towards a VFS that will support WAL. Locking code is in place
but is untested.  Still no support for the DMS.

FossilOrigin-Name: 1bde41cf081570ad257f927b641e752dff4ed014
2010-04-29 15:17:48 +00:00
dan 185cca609b Close all open database connections at the end of wal.test.
FossilOrigin-Name: 3cc55a7568daa3796483f632e33478969e381cf5
2010-04-29 14:58:53 +00:00
dan 31c03907fd Fix a but in the WAL checkpoint code causing SQLite to use an inconsistent cache in a subsequent transaction.
FossilOrigin-Name: d1cadeed4eea20d8892726cc8c69f4f3f57d0cd4
2010-04-29 14:51:33 +00:00
dan b4e3a6f72f Add tests to walthread.test.
FossilOrigin-Name: 9e891e7543ea4d7dee76deb2456af940f4cac49b
2010-04-29 08:47:28 +00:00
dan e45d442692 Add a test to walthread.test for changing between WAL and rollback modes.
FossilOrigin-Name: da229e44bd4a5d512261da05958d560808c9889f
2010-04-28 18:17:23 +00:00
dan f032f5362e Merge two "wal"
leaves.

FossilOrigin-Name: 13d2d5a66e9eaa81aa6314354201ee1fbd2b3824
2010-04-28 17:49:57 +00:00
dan 5e0ce87a3f Change walthread.test so that tests can be run with either multiple threads or multiple processes.
FossilOrigin-Name: 25f85f68723e56c18e44b094d85f67b99912dc86
2010-04-28 17:48:44 +00:00
drh 9beb1584bd Changes to the interface design for the xShmLock method of the VFS.
FossilOrigin-Name: 348409de26eafe12f5cb1236e8e167a4183d4051
2010-04-28 17:21:33 +00:00
drh 833bf968e3 Rename the sqlite3_log_hook() to sqlite3_wal_hook(). Added comments to
wal.h.

FossilOrigin-Name: bbc385111b19071e20fe963fab814262c815b3e9
2010-04-28 14:42:19 +00:00
dan 4b64c1e365 Merge two "wal" leaves.
FossilOrigin-Name: 8c2d43babd61fe2225d5c402174253f412604092
2010-04-27 18:49:54 +00:00
dan 8b348af860 Add a test to check that a checkpointer releases its locks before returning, even if it has been prevented by a conflicting lock from checkpointing the database.
Add a test to check that a checkpointer releases its locks before returning, even if it has been prevented by a conflicting lock from checkpointing the database.

FossilOrigin-Name: be44349d2b790fb470fcc9fb6a12e8b1076dc645
2010-04-27 18:43:16 +00:00
dan 8b5444bfae Fix a problem with identifying a corrupt database in WAL mode.
FossilOrigin-Name: c8658da44671e9c43c90ee4857bbe82c55d40f25
2010-04-27 14:37:47 +00:00
drh af75c8695b Add the xShmRelease() method to the VFS. The os_unix.c implementation of
the shared memory logic is still non-functional.

FossilOrigin-Name: ed715b47c5f7657fbf901805981867898054b14d
2010-04-27 11:49:27 +00:00
dan e106de6317 Run trans.test and avtrans.test as part of the "wal" permutation.
FossilOrigin-Name: c8893310510148f7e71ede5691606b6fc1c3df4d
2010-04-27 06:49:34 +00:00
dan 31f98fc8e4 Fix a problem that occurs when one process causes the log-summary file to grow and then a second process attempts to read the database.
FossilOrigin-Name: b51a5f8bc660616aa264025dd7ad4bdab458814b
2010-04-27 05:42:32 +00:00
drh 29d4beccc0 Merge in recent changes from the trunk
FossilOrigin-Name: 7a0ac682c3bffcb345321fe97434563350ac90f9
2010-04-27 01:56:21 +00:00
drh 8c6f666b26 Optimization: Convert an ORDER BY clause into a no-op if the query also
contains a GROUP BY clause that will force the same output order.

FossilOrigin-Name: ca9d86baf70f210d331ce93102177c8005c494cb
2010-04-26 19:17:26 +00:00
dan e180c296ea Do not attempt to set journal_mode=wal on :memory: or temp file databases.
FossilOrigin-Name: 30d0134454734fd9335896372c30a903e9adcc64
2010-04-26 17:42:56 +00:00
drh 93791ea0ba Change the default_cache_size pragma to always store a positive value.
FossilOrigin-Name: 36fb2cae75b5dfe1fe818895f03c0b4f4190a722
2010-04-26 17:36:35 +00:00
drh c6d2b4a365 Identify the SQLite version meta-value entry in the db-header output of
showdb.

FossilOrigin-Name: 245d934b72cbc6e897193e7892195b6561995939
2010-04-26 17:30:52 +00:00
dan 4cd78b4d89 Fixes for problems with small caches and SAVEPOINT rollback in WAL mode.
FossilOrigin-Name: 6a944f028d4a070bef29e1fbc6fbef481ebcd34c
2010-04-26 16:57:10 +00:00
drh 7ecc14761e Further enhancements to the showdb utility: A page number followed by "b"
causes a btree decoding to occur on the page.

FossilOrigin-Name: 2ff824e58ce8b8f605c809ac960dcbfc51c30e30
2010-04-26 16:47:12 +00:00
drh 562cedb185 Enhancements to the showdb.c utility program. Automatically detect the
page size and adjust the display accordingly.  Add the "dbheader" display
option.

FossilOrigin-Name: 23eb408b5d08b89b41aaf245a7be8e235f30af8a
2010-04-26 15:44:07 +00:00
dan 71cb518fca Add the "wal" permutation to run existing test files savepoint.test and savepoint2.test in WAL mode.
FossilOrigin-Name: 205e5d8ac08f7d7853427b4cd235fca125155d2d
2010-04-26 12:39:03 +00:00
dan cd11fb28c3 Add mutexes to fix a race condition in wal.c. This isn't a very good fix.
FossilOrigin-Name: 3d159939cc2beb18c4ca0c8e9a99a75d4107e6e4
2010-04-26 10:40:52 +00:00
drh c438efd68a Change the names of the log.c and log.h source files to wal.c and wal.h.
FossilOrigin-Name: 56fe5d7624f840417152bcc63efbe21a5f557920
2010-04-26 00:19:45 +00:00
drh f2424c521b Begin moving WAL-specific I/O into the VFS. This checkin contains VFS
infrastructure but it is untested and is not yet hooked up to the WAL.
The version number is bumped to 3.7.0 because of the VFS extension.

FossilOrigin-Name: f5e615c28c7035a7e6d896790b51cf9bc7371d5f
2010-04-26 00:04:55 +00:00
drh a4741840f6 Remove an unreachable branch from the function initialization logic.
FossilOrigin-Name: 064d3ddd6199b7b049b1706974e4295f78fb5ab9
2010-04-25 20:58:37 +00:00
dan 56d95913eb Add comment explaining checksum mechanism.
FossilOrigin-Name: 3e9ef5153ebf0543ad0f75a7561f73d22171da53
2010-04-24 19:07:29 +00:00
dan 74d6cd887f Fix bugs in WAL mode rollback.
FossilOrigin-Name: 31215969f59be536fe87431bb9fbfa7d13027e35
2010-04-24 18:44:05 +00:00
dan 9de7943783 Merge with [0291ed974d].
Merge with [0291ed974d].
Merge with [0291ed974d].

FossilOrigin-Name: a352f6285e33a806fbe4475e720e763fdc5bb47d
2010-04-24 14:33:08 +00:00
drh 545f587fc8 When commands such as ALTER TABLE and VACUUM use SQL internally, make sure
they use only the built-in functions and not application-defined overrides
for those functions.

FossilOrigin-Name: 0291ed974d5bf1e344e2c38422530cc961b897da
2010-04-24 14:02:59 +00:00
dan 4f08d4b848 Merge with [e79dac3c2f].
FossilOrigin-Name: 1e793d3a6d46ec5d744e077b10362e7cfa118eef
2010-04-24 04:53:15 +00:00
dan ff207012e6 Reserve some space at the start of the log-summary file to apply locks to.
FossilOrigin-Name: a031aa1fa01f062b087154833738f011f7bc4eb5
2010-04-24 04:49:15 +00:00
dan 3306c4a945 Fixes and tests for backup of a WAL database.
FossilOrigin-Name: 480d12db4c0ebcc37598f7620d39193875eab15b
2010-04-23 19:15:00 +00:00
shaneh 9a6e897328 Merge of notify.c changes from experimental.
Reset stored blocking connection when registered unlock_notify callback is cleared.

FossilOrigin-Name: e79dac3c2f723ed7cc62fcef468f53952711f242
2010-04-23 14:29:04 +00:00
dan d5c99c3939 Add very simple test cases for backup and VACUUM of WAL databases. More to come.
FossilOrigin-Name: 1077d8130b8ed5716ad73f78382270909d347963
2010-04-23 11:44:40 +00:00
dan ce4f05f374 Create a version of the log checksummer that works on big-endian platforms. Remove the 512KB size limit on the log-summary.
FossilOrigin-Name: 5d6d4423d1def39bd2424703120aa985085c3f8e
2010-04-22 19:14:13 +00:00
dan ede6eb8d1d Further tests and changes related to switching between WAL and rollback modes.
FossilOrigin-Name: 1236318477787a612f02cc98caf2931bd2e99d94
2010-04-22 06:27:04 +00:00
dan b978002743 Tests for (and changes to) the code to switch between WAL and rollback modes.
FossilOrigin-Name: 9f4f933f2c6596064fcfc7fb5add87e8c5b57448
2010-04-21 18:37:57 +00:00
dan a470aeb4ac If, after obtaining a SHARED lock, there exists a *-wal file in the file-system, use WAL mode. This is necessary to recover from a crash that damages the first page of the database file.
FossilOrigin-Name: 33cabf271b8f4dda508a610bf59964273fe2cb84
2010-04-21 11:43:38 +00:00
dan 28e5386f79 Minor changes to test cases to account for the fact that databases with read/write versions of 2 are now understood.
FossilOrigin-Name: 278ed41e1d4bbff9544cb2cf4cf52dbbcf0c17df
2010-04-21 06:19:12 +00:00
dan e04dc88be5 Use the read and write version fields of the database header to mark a database as operating in wal-mode.
FossilOrigin-Name: 96bef18c1411c3e0348295886f105e1646c46320
2010-04-20 18:53:15 +00:00
dan 8d22a17411 Add the sqlite3_log_hook() interface for scheduling checkpoints.
FossilOrigin-Name: 9bda601455705475075e33bfa85687bce34b15ff
2010-04-19 18:03:51 +00:00
dan 54934f4689 Add some comments regarding file-locks to log.c.
FossilOrigin-Name: 9d51c3b754f0b94fea5ef3d669ad583b93b2b024
2010-04-17 18:50:27 +00:00
dan c511878955 Do not sync any files in wal mode if "PRAGMA synchronous=off" is set. If files are synced, pass either SQLITE_SYNC_FULL or SQLITE_SYNC_NORMAL to the xSync() callback as configured by "PRAGMA fullfsync".
FossilOrigin-Name: 0ae91b0008b242a47385fc1f295c6b645483ee22
2010-04-17 17:34:41 +00:00
drh 335c0faabd It is possible for sqlite3.pUnlockConnection to be non-NULL when
sqlite3.pBlockingConnection is NULL, as the notify1.test script
demonstrates.

FossilOrigin-Name: 95ff76ef67d6189f54375973fa485d6eb464b029
2010-04-17 16:10:19 +00:00
dan dea0a85091 Merge with trunk commit [3e646e3f4c].
FossilOrigin-Name: 43463970f5885fb116588695146f2a56cb22804a
2010-04-17 15:45:35 +00:00
dan 6703239d2f In synchronous=normal mode, do not sync the log after every transaction. In synchronous=full mode, sync the log and add any extra frames required to avoid blast-radius related problems after each transaction.
FossilOrigin-Name: 9bc9b6847303d0324543a9ded8dd0473490122d8
2010-04-17 15:42:43 +00:00
drh 3674bfd1b6 Change sqlite3_step() so that it automatically calls sqlite3_reset() instead
of returning SQLITE_MISUSE when invoked on a prepared statement that
previously returned any value other than SQLITE_ROW.

FossilOrigin-Name: 3e646e3f4cd0ca288e444561e951cecfdaee2ab5
2010-04-17 12:53:19 +00:00
dan 3de777fd8c Enhancements to wal-mode locking scheme.
FossilOrigin-Name: 8549c286497f3d2cd118be1334fce00d6f8a26c4
2010-04-17 12:31:37 +00:00
shaneh 4b93f6bd1e Changes for branch coverage of notify.c. Fixed quirk of
unlock_notify() where it would still think it was blocked
after a callback was cleared (even after the transaction
on the blocking connection was closed).

FossilOrigin-Name: c54e8dad01b0ecaf8d66b10e64e862dcad8a6746
2010-04-16 22:05:31 +00:00
dan 97a313554d Change the log file format to include a small (12 byte) header at the start of the file.
FossilOrigin-Name: 9865d14d6041874bc1239ce7a061d5c75f2d33c9
2010-04-16 13:59:31 +00:00
dan 4a4b01dc1c Fix bug in log recovery (last frame in log was being ignored). Also remove an incorrect assert statement.
FossilOrigin-Name: 67d2a89ec2d593a077eb19a6ea2b06cb1c2e9ba8
2010-04-16 11:30:18 +00:00
drh f391327824 Disable query flattening when the outer query is a compound SELECT and
the inner query has a LIMIT clause.  Ticket [02a8e81d44].

FossilOrigin-Name: f96782b389b5b97b488dc5814f7082e0393f64cd
2010-04-15 23:24:29 +00:00
dan 4cc6fb6165 Allow writers to write dirty pages to the log mid-transaction in order to free memory.
FossilOrigin-Name: ecd828f96909895535d7dc744e5a8530e234e04d
2010-04-15 16:45:34 +00:00
dan bb2e9c97fc Merge two leaves on the WAL branch.
FossilOrigin-Name: c9ed66cc3994b3b0d67a6c950b552a1a869f2ed2
2010-04-15 13:33:18 +00:00
drh ed808acd1b The query planner fix of check-in [33b1f584ef] should have been on the trunk.
FossilOrigin-Name: f538d759beda67e042b66181b65bd432488f7650
2010-04-15 13:29:37 +00:00
drh 521a72b1fa Fix a problem in the result set size estimation logic of the query planner -
a problem introduced by the two previous changes.

FossilOrigin-Name: 33b1f584ef712625c4df8e2aefe895fa89f6a795
2010-04-15 12:36:06 +00:00
dan 39c79f587c Change the way checksums are calculated.
FossilOrigin-Name: 84955c2e9ce526c5a3ed479aa09f093a7e37c7d0
2010-04-15 10:58:51 +00:00
drh ce2f88d95b Bring over the recent query planner enhancements from the trunk.
FossilOrigin-Name: 82969f27e5ea843cb379666d8a02e4a3fddc03b2
2010-04-15 02:37:10 +00:00
drh ed754ce2cc Further refinements to table order selection on join query planning.
FossilOrigin-Name: defaf0d99a807027f8883bf821b6482025f9f54e
2010-04-15 01:04:54 +00:00
drh 1e0f4a83d6 The query planner uses non-indexable WHERE clause terms to reduce the
estimated number of output rows, then uses the estimated number of output
rows as a tie-breaker when choosing table order.

FossilOrigin-Name: b87cb0c2bd9c52a938795a974e101879b81210e3
2010-04-14 19:01:44 +00:00
dan 49320f8568 Add tests and fix bugs in WAL locking mechanism.
FossilOrigin-Name: c18077f2465fc34830f11c9832e76be5746eaeea
2010-04-14 18:50:08 +00:00
dan e264d983d1 Add tests to check inter-process WAL locking.
FossilOrigin-Name: 9435f3135849e0d38fde1669201db508561a6308
2010-04-14 18:06:50 +00:00
dan 02bb596649 Improve the logLockRegion() function in log.c.
FossilOrigin-Name: 5e9dd3bd8e829376408925fb4cfcd5bb1eb1105f
2010-04-14 15:49:40 +00:00
dan b9bf16bfde Fixes for locking issues in WAL mode.
FossilOrigin-Name: a9617eff39177250e2f118f25fdd4b3acb8b0478
2010-04-14 11:23:30 +00:00
dan 64d039e512 Add experimental locking scheme.
FossilOrigin-Name: 3f958e87c33d667d299b03ffdef58db5dc6363f4
2010-04-13 19:27:31 +00:00
drh 622194c0d2 Fix an uninitialized variable in readDbPage of pager.c.
FossilOrigin-Name: f4e1150fed2c520c7c52612cb1019429d78dc32a
2010-04-13 15:30:53 +00:00
dan f05c86dd73 Remove old code to interpret an argument (no longer used) to "PRAGMA checkpoint".
FossilOrigin-Name: 27dc5977c19e717afd65d3805557e38dec7bedcb
2010-04-13 11:56:03 +00:00
dan 80a1526a9a Fix other problems in the WAL test scripts.
FossilOrigin-Name: dcb31181db246dd3f81ce63b144dd0cf95f06ee3
2010-04-13 11:45:31 +00:00
dan d3f8f94652 Fix test script issues preventing walthread.test from running.
FossilOrigin-Name: d90b1dde0702ceb0eae2a3da36733a7e5b1a6b3a
2010-04-13 11:35:01 +00:00
dan 9281bf2a9f Fix a pager bug introduced by the wal code.
FossilOrigin-Name: 4a0b29dc5e573a5d696ede17db5d7acf8d23aa98
2010-04-13 11:18:40 +00:00
dan 835ae8bcdd Sync wal branch with [012cf101bf].
FossilOrigin-Name: 9d690f24f634696f76fa38372461cfa69263e91e
2010-04-13 06:20:45 +00:00
dan c9206ed56e Test that the rollback-hook is invoked if a commit-hook implementation returns non-zero (causing a rollback). Remove documentation comment that says otherwise from sqlite.h.in.
FossilOrigin-Name: 012cf101bf8be9e39c138786ea5a5039b8131e55
2010-04-13 06:18:02 +00:00
drh 08ede1d08b Add e_fts3.test to the set of tests excluded from the inmemory_journal
exclusion list, since it does simulated OOM errors which trigger I/O errors
and SQLite is unable to recover from I/O errors without a persistent journal.

FossilOrigin-Name: e7e7127f0b0db582274338a9fefc30a0c0be07c3
2010-04-12 20:54:13 +00:00
drh 09c0f6d02d Recent changes cause the xSync method of the memory journal implementation
to be used, so remove the assert(0).

FossilOrigin-Name: 1f2cb9402838373f6370660dfc885013df079895
2010-04-12 19:44:22 +00:00
drh 02927cc1f3 Clear a global variable in e_fts3.test before it is used.
FossilOrigin-Name: ae89dfd26b65fb1a3633a4338f5cb5e54a7d2035
2010-04-12 19:43:43 +00:00
drh 63ca1dba52 Remove duplicate secure_delete pragma implemention.
FossilOrigin-Name: c15fda145b621fc86402914aa5b015e53590555a
2010-04-12 19:31:59 +00:00
dan 6700d02cce Add "log.h", which should have been part of the previous commit.
FossilOrigin-Name: 8de9f010044fc992b5b45a7bb0da1284b404ecdb
2010-04-12 19:05:58 +00:00
dan 7c24610e64 Import experimental write-ahead-logging code.
FossilOrigin-Name: 409d61baeb0a19d1700c973f16c8acef7b8506cd
2010-04-12 19:00:29 +00:00
dan eada58aa49 Fix a problem where a process in exclusive mode could delete a hot-journal file without rolling it back from within sqlite3_close() or DETACH. This problem was introduced by the previous commit, it is not present in any releases.
FossilOrigin-Name: 51a613950824698687c0db83b7884db33d45f7f5
2010-04-12 17:08:44 +00:00
drh 47f18f7294 Reset the simulated device in the test harness to its default
configuration whenever it is restarted.

FossilOrigin-Name: 562d20e662da474ea326165730ecfdfcf9b414ee
2010-04-12 14:51:10 +00:00
drh 91781bd72f Fix issues and clarify the operation of pager_playback_one_page().
A block comment in pager.c identifies 13 invariants on the pager subsystem.
Ticket [9d68c883132c8].

FossilOrigin-Name: 0906597698b697ab2993a460f257e326cb58e475
2010-04-10 17:52:57 +00:00
drh f762593eaa Add a test case for the OOM-fault corruption issue.
Ticket [9d68c883132c8].

FossilOrigin-Name: 0a64a937b583c32c02c83fc669addf79662efea8
2010-04-09 23:05:24 +00:00
drh 05f69dd388 Candidate fix for a pager bug associated with sqlite3PagerMovepage().
FossilOrigin-Name: 8c046eb6d16682d5e755624deb4f76f57350b9c9
2010-04-09 15:34:06 +00:00
drh 6498f0bb2e Avoid unnecessary calls to sqlite3_step() with null prepared statements
while parsing the schema.

FossilOrigin-Name: ae04d2d15d3d96f607adb394a631d96cd4cf2c1d
2010-04-09 09:14:05 +00:00
drh 9e48165b07 Fix a typo in a comment. No changes to code.
FossilOrigin-Name: 332cb55113a621456c6522830585434146c388e7
2010-04-08 17:35:34 +00:00
drh f12cde5637 Fix code coverage problems in where.c.
FossilOrigin-Name: b04a52824971e8880e4bf0d9862db4eef8b607ab
2010-04-08 17:28:00 +00:00
drh c71b5f34c9 Additional automatic index tests.
FossilOrigin-Name: 99d8e325e9eb8905631b06676206e6412f386d08
2010-04-08 16:30:38 +00:00
drh 7caba669a6 New test cases for automatic indices. New testcase() macros associated
with column-used bitmasks.

FossilOrigin-Name: e1aa48ace7e43c3805278120b8228ee597e2cee7
2010-04-08 15:01:44 +00:00
drh 8bd5412b90 Fix the computation of the number of rows in a table during automatic
index generation.

FossilOrigin-Name: edeab06a5010c82491a6cc9393cf2a35a7622ac5
2010-04-08 15:00:59 +00:00
drh 67ae0cb231 Fix an integer overflow bug in the automatic index logic. The bug was
detected by the testcase() macros added in the previous check-in.  Also
add some more testcase() macros, since this issue points up their importance.

FossilOrigin-Name: af97b4881a8f010055cde672634141d7ed6898fc
2010-04-08 14:38:51 +00:00
drh 52ff8ea605 Add testcase() macros to the automatic index logic to insure that boundary
cases are tested.

FossilOrigin-Name: 7286547847721b8f5f64bc2e7dc236652b1ae985
2010-04-08 14:15:56 +00:00
drh 9d6caca80d Make sure F_OK, R_OK, and W_OK are defined in test_demovfs.c. Define them manually
if they are not.  This is necessary to get the module to compile on some systems.

FossilOrigin-Name: 7c8afc3272fa91e2b5685b009eb674dbc1b5920d
2010-04-08 11:35:18 +00:00
drh 5c56f70199 Merge automatic index changes into the trunk.
FossilOrigin-Name: bf7b8d863665870a38f0b2335cc71de856a515b4
2010-04-08 01:16:19 +00:00
drh 0013e72edf When constructing automatic indices do not include the same column more than
once.

FossilOrigin-Name: d067d9f7a9138e026c1018361127e34385928657
2010-04-08 00:40:15 +00:00
drh 5a8aedab2d Pull over the latest changes from the trunk.
FossilOrigin-Name: e388fe8be878c80ef0bfd1699a7268cdb22cb3c6
2010-04-07 20:32:18 +00:00
drh d14133e3f4 When rolling back a savepoint to the beginning of the transaction, make sure
to initialize the database size in the btree layer correctly even if the
database size field of the header is zeroed.

FossilOrigin-Name: a3540c6acf2bb6bdd44c101b63f17ca85e6b68ed
2010-04-07 20:29:56 +00:00
drh 3c379b0101 Add an interface to the SQLITE_STMTSTATUS_AUTOINDEX status information
to the TCL bindings.  Add some simple automatic index test cases.

FossilOrigin-Name: 1f40441204d9a912b1d6b67ff6ff9e17146c7abd
2010-04-07 19:31:59 +00:00
drh c633908199 Wrap all automatic index changes inside SQLITE_OMIT_AUTOMATIC_INDEX. Add
the automatic_index PRAGMA to turn it on and off.

FossilOrigin-Name: a811a47fbe4f757a7ab575ae5a0f65177a3f07c0
2010-04-07 16:54:58 +00:00
drh 4139c99eba Make sure that all automatic indices are covering indices. Otherwise, the
table and index might be used together in a query but the table could get
out of sync with the automatic index through out-of-band changes.

FossilOrigin-Name: 2364313142668b3d0ad144447b4862709be929cd
2010-04-07 14:59:45 +00:00
drh 2a6a7eeba5 Enhance comments on the SrcList object definition to better explain the
operation of the SrcList.a[].colUsed field.  No changes to code.

FossilOrigin-Name: c0f67ea131c3e237e46311b1a3dcb3febf2ea036
2010-04-07 14:33:07 +00:00
drh ab5cd70ae5 Fix the trace output of the OP_Function opcode to show the correct
register numbers.

FossilOrigin-Name: 064c283eee82c5053e84058a0e1908e468da6ce3
2010-04-07 14:32:11 +00:00
dan 0a7a9155a4 Add file test_demovfs.c, containing a simple VFS implementation that demonstrates how writes to the journal file may be safely buffered by the VFS layer to improve performance on some embedded systems.
FossilOrigin-Name: af3b72d94a1b6513f02402af3ada5fb5dd390151
2010-04-07 07:57:38 +00:00
drh a21a64dd0c Veryquick.test is now working. The SQLITE_STMTSTATUS_AUTOINDEX counter
added.

FossilOrigin-Name: abbf16e5e7895971710fb3a8fd9c782fc1218a77
2010-04-06 22:33:55 +00:00
drh 75bb9f5a5b Runs quicktest without hitting an assert now. Some tests get unexpected
results still and there is a memory leak.

FossilOrigin-Name: a8224448cc305258a59a9023e6604783dda73e45
2010-04-06 18:51:42 +00:00
drh 424aab88ca Progress toward getting automatic indices to work. Still failing in corner
cases.

FossilOrigin-Name: ac6d0fba78eb9dcd69372e128d4a039aaff4b417
2010-04-06 18:28:20 +00:00
drh 8b307fbfa0 Automatically generate transient indices for tables in joins that would
otherwise have to use a full table scan.

FossilOrigin-Name: 1b2a04125f964e14f3fb90171c5ab86a0641d1c9
2010-04-06 15:57:05 +00:00
drh 25d3adbb6a Minor comment changes to the OP_OpenEphemeral header. No changes to code.
FossilOrigin-Name: 8e1d7ef47f643503aa823d9986a931a83c63648b
2010-04-05 15:11:08 +00:00
drh 8d83c0fdd5 Silently abandon a rollback if the journal has been truncated.
FossilOrigin-Name: 7626f6c9ea04d1a5690dd11bb13e8c3c04e3b0f5
2010-04-03 13:08:09 +00:00
drh 34e2b837d5 Check for a failure in the call to sqlite3PagerPagecount() from within
sqlite3PagerWrite().  (Error discovered by valgrind.)

FossilOrigin-Name: d64d181c79aee3501be6f7eb8c11ab2cc9a8d63c
2010-04-02 13:25:22 +00:00
drh a378c566d2 Take care to avoid a buffer over-read when adding a KEYINFO structure
to the P4 parameter of an opcode.

FossilOrigin-Name: 937b931a7cdad6874638158ed6a9ab6356b0bd0c
2010-04-02 12:55:38 +00:00
drh c2a4bab462 If the size of the database according to the header is larger than the
actual database file size, report that the database is corrupt.

FossilOrigin-Name: 8eb1f2443f2712920452b7ed3fb835c7f3221191
2010-04-02 12:46:45 +00:00
drh cce75d3343 Pager changes for code coverage testing.
FossilOrigin-Name: b04a45ea9714e7a35372b5d6a58868b307d10502
2010-04-02 03:38:59 +00:00
drh 4d077f9255 Disable the corruptE.test script when ENABLE_OVERSIZE_CELL_CHECK is on.
FossilOrigin-Name: 1dc4f9fe9b83467ba014e759b93f6caa2925e4d2
2010-04-01 18:33:14 +00:00
drh 43377f5ad5 Zero the filesize-in-header word for bigfile.tcl. Remove bigfile.tcl from
the journaltest permutation.

FossilOrigin-Name: 63610c71ca629de5e81950bc3c2ee6014e67853b
2010-04-01 16:15:56 +00:00
drh 45b355dc4f Do not journal the content of freelist leaf pages. This restores an
optimization that was accidently undone by check-in [12f7346c13] on
[2009-01-20].

FossilOrigin-Name: b1e7a1a677e1c2a6c2ab83a67070605465a3e495
2010-04-01 13:41:10 +00:00
drh 9afb1abe42 Remove a NEVER in sqlite3PagerPagecount() that can in fact be true.
FossilOrigin-Name: 8f00533782a0eae5613caaf86608384cb702fc51
2010-04-01 02:47:01 +00:00
drh 1f5b467f13 Restore the size information in the BtShared structure when a transaction
rolls back.

FossilOrigin-Name: 802aeb30c9baf4059fa84f4693f290f80d3a4085
2010-04-01 02:22:19 +00:00
drh a792dc5c4a Make sure an OOM error on sqlite3PagerPagecount() is detected and reported
out to the interface.

FossilOrigin-Name: 8aecf302a5aac66e43a8cc6c4e0d917f74e9e0de
2010-03-31 23:20:04 +00:00
drh 8d8626fe2b Report corruption if a database contains a reference that is out of range
according to the filesize-in-header database size.

FossilOrigin-Name: a91db0b1cd0b0fbadc5c8fe2eb8863629b411d87
2010-03-31 20:29:06 +00:00
drh afc266a76a Clarification of the implementation of SQLITE_STMTSTATUS_FULLSCAN_STEP.
No logical code changes - just commenting and layout changes to improve
readability.

FossilOrigin-Name: 06b9ca32255572a699dc51f46f848d0bf01255e1
2010-03-31 17:47:44 +00:00
dan 67a6a40cf9 Clear the column cache before populating aggregate accumulator registers. Fix fo
r [883034dcb5].

FossilOrigin-Name: ffc23409c7fb45dc5a8722fad26e26d207bb3213
2010-03-31 15:02:56 +00:00
drh d3d986d329 Documentation enhancements for the sqlite3_log() interface. No functional
changes to code.

FossilOrigin-Name: ba13a11108d7852c61f959cc8a5fc39c25202cae
2010-03-31 13:57:56 +00:00
drh 4b4580b701 Include shell.c and sqlite3.def in the amalgamation ZIP archive.
Ticket [e063139eb3f8]

FossilOrigin-Name: 0077ed5cf4e56eb81cfa850fc98e6b033708fc03
2010-03-31 11:52:57 +00:00
drh 97b59a56d2 Increase test coverage following the introduction of the new
filesize-in-header logic.

FossilOrigin-Name: dbc2c3c0144d2c76aec04f80892302c532947dc8
2010-03-31 02:31:33 +00:00
drh b1299158c7 Continuing refinements to the filesize-in-header enhancement.
FossilOrigin-Name: 79e22b95038c50b9b7f35e09262805ff6338b59b
2010-03-30 22:58:33 +00:00
drh bf59283ba2 Add a NEVER macro around a test in btree.c that can not longer be true.
FossilOrigin-Name: c117f99236a009778bb7878da464918554391f0a
2010-03-30 15:51:12 +00:00
dan 7ba4597135 Do not crash when compiling an "INSERT INTO tbl DEFAULT VALUES" when tbl has either BEFORE or INSTEAD OF triggers attached to it. Ticket [f3162063fd].
FossilOrigin-Name: ca359a3e8048bd11605c41c4b48134c0343e543b
2010-03-30 12:40:32 +00:00
drh d454214ddd Change an #if into an #ifdef.
FossilOrigin-Name: 371bab5d6534860ce908e52129c64a49946be33a
2010-03-30 11:57:01 +00:00
drh 4b11b0897a Pull the experimental file-size-in-header changes into the trunk.
FossilOrigin-Name: 0092b36c7bbd04bf3826de7805e8a14739390f31
2010-03-29 21:22:00 +00:00
drh 25a80ad0b1 The btree layer now tracks when a database is empty at the start of a
transaction and rolls back to that state.

FossilOrigin-Name: 01ef6c1944507c188a83a434ff00e98ad767f744
2010-03-29 21:13:12 +00:00
drh 5e0ccc216d Fix issues with the io.test script. There is still a problem with a
ROLLBACK TO not working on an initially empty database files.  And much
more testing is needed.

FossilOrigin-Name: 09786e2a51817d572a01ae7f3621f03fd27fc363
2010-03-29 19:36:52 +00:00
drh dd3cd977cc Experimental changes that cause SQLite to use bytes 28..31 of the database
header to determine the database size, rather than using the actual database
size.  This allows database space to be preallocated.

FossilOrigin-Name: b844ac6fcb72595a71e5c5283ec461309a87ba79
2010-03-27 17:12:36 +00:00
dan c26c00495f Increase the estimated cost of using a virtual table as the outer loop of a join when there exists an ORDER BY clause that is not satisfied by the virtual table. Fix for [775b39dd3c].
FossilOrigin-Name: 9e075e70f0e2a1ad302d17150cd58f91669a97a6
2010-03-27 09:44:42 +00:00
shaneh 1141ae2463 Fix OOM error on ANALYZE with STAT2 enabled with zero-length data. Ticket [cbd054fa6b].
FossilOrigin-Name: c33b38b59f733494ca0bce3f59a669fe7ed76b9f
2010-03-26 01:54:33 +00:00
dan 6d3cb2fbae Fix for [9861b74ab9]. Correctly handle strings with zero tokens in the fts3 offsets() function.
FossilOrigin-Name: d37034f7fc46b83be681247fde97823736c994cc
2010-03-24 15:57:33 +00:00
drh 280799b4ff Attempt to suppress a warning from Borland Code Guard.
FossilOrigin-Name: be278979917336e7186d7830876180154b5280ba
2010-03-24 11:55:08 +00:00
drh 7bca0a3660 More commenting and documentation enhancements in FTS3.
FossilOrigin-Name: 892e286709c4a72aae364b85dd43bea525bb1b4d
2010-03-23 18:24:06 +00:00
drh d6291c9155 Fix up obsolete comments in FTS3 to conform to the latest nomenclature.
Add new comments to better explain FTS3 operation.

FossilOrigin-Name: 3e4a0082170155b5b779afd075a3ee650530ca68
2010-03-23 15:46:41 +00:00
drh 486ff4897e Close the auxiliary database db2 at the end of the crash8.test script.
FossilOrigin-Name: 0fbdc431e832200efd87efd68456d5906397a219
2010-03-23 15:29:49 +00:00
dan e07b606522 Add an extra test case for crash recovery.
FossilOrigin-Name: f2326dad4e47b2657be302e194970967960eb1c0
2010-03-22 17:38:11 +00:00
dan bb23e7f91b After a rollback that writes or truncates the database file, sync the database file before invalidating the journal contents.
FossilOrigin-Name: b21b911f233842357af9ccc14525bbd48a38edb1
2010-03-22 17:13:53 +00:00
drh acd63a5a62 Disable the "init.test" test script when compiled with SQLITE_THREADSAFE=0.
FossilOrigin-Name: ad68fa65bbd6b82e69fe8c36e4c459ea2ced0f8c
2010-03-22 15:47:38 +00:00
dan 98f0c3619f Change the formatting of the preprocessor macros surrounding the compileoption interface in sqlite.h.in. This is so the documentation produced by parsing this part of sqlite.h.in is formatted similarly to the docs for the deprecated interfaces (with the #ifndef visible on the webpage).
FossilOrigin-Name: 161958d11f2ef6ce4d7ba69afea03e0a6764cc1b
2010-03-22 04:32:13 +00:00
drh f3609eeba7 Put an ALWAYS() around a condition in pcache.c that must always be true in
the current implementation.

FossilOrigin-Name: 88810cd091b33f2c56f842e32cafbac5d34d7412
2010-03-19 19:23:51 +00:00
dan 3f0d9d3846 Have the xUpdate() method of the rtree module virtual table implementation set the *pRowid output variable when inserting a row. Fix for [dd3ba6063a].
FossilOrigin-Name: f31d22489d44701c89cb13c663dfa1a6cc04f900
2010-03-19 19:02:27 +00:00
drh f92a4e35c5 Store the SQLite version number of the last writer in bits 96..99 of the header.
FossilOrigin-Name: 146d4f5d3459235d8b2d27a5d77beb7645f75185
2010-03-19 16:55:47 +00:00
drh e9c2d34c5b Make sure the in-journal boolean vector is cleared and released when ending
a transaction.  This fixes an obscure problem with the previous check-in.

FossilOrigin-Name: 69d749d93d6565b848ce5c07f2738d144c6564bf
2010-03-19 16:52:53 +00:00
drh ba726f4939 Do create, open, or initialize the rollback journal until something actually
needs to be written into the journal.  That way, expensive filesystem
operations are avoided if the transaction ends up being a no-op.

FossilOrigin-Name: b78e58ae1570ab4d66a69db445a752c6456038a0
2010-03-19 15:48:13 +00:00
dan 3b6f4c06ac Rewrite a couple of queries used internally by FTS3 to take advantage of the "SELECT max(x) FROM ..." optimization.
FossilOrigin-Name: b7e42ae77443b33e0ab83265064830594094dc7c
2010-03-19 06:59:19 +00:00
drh 71663ad0c1 Mark internal routines as "static" in FTS3.
Ticket [b1552d0fa7].

FossilOrigin-Name: 39b34ac4a7bd06144b3630c0ad71bad0615418b6
2010-03-18 16:34:44 +00:00
drh 3a3dd3ac8d Improved error message when the right-hand operand of MATCH in FTS3 is
not a valid search expression.  Ticket [170872f1c3].

FossilOrigin-Name: bea9258643edfeb98ebf59d93fa18a14e4221fea
2010-03-15 20:53:01 +00:00
drh 9396a41e6e Fix FTS3 so that it does not run illegal SQL and cause a spurious log
message.  Ticket [42d45a693e6].

FossilOrigin-Name: f186b6a61909be1d65b76a6fbaa42f57bbd0d1e5
2010-03-15 19:27:55 +00:00
drh ed37690afd Store the database size in pages in bytes 28..31 of the header. Currently
this is for forensic use only, but it might be used in the future.

FossilOrigin-Name: 59f75bba028e1107ed41d447c27aef31a6656b68
2010-03-13 02:15:49 +00:00
drh 107b56e86d Add assert()s to mem2.c (activated by SQLITE_MEMDEBUG) which verify that
memory alloctions that might have come from lookaside are always freed
using a lookaside-aware free routine.

FossilOrigin-Name: c2af2164cf7b279ebb3e08201561348be6e765df
2010-03-12 16:32:53 +00:00
drh 735b9cbb96 Move the ctime.c source module near the beginning of the list of files
inserted into the amalgamation so that #defines that are overridden in
other modules will not effect the values returned by
sqlite3_compiletime_used().

FossilOrigin-Name: bb591802fff5a99ae504509e812bb34e762eaef0
2010-03-10 23:13:53 +00:00
drh 63da089314 Add the SQLITE_DBSTATUS_CACHE_SIZE verb for sqlite3_db_status(). The
highwater mark does not yet work on this verb.

FossilOrigin-Name: 418c6d8113bc337556b0d47acfd6a7d865d1121f
2010-03-10 21:42:07 +00:00
drh 9f8da32662 Remove the "experimental" markings on most interfaces that have been around
for multiple releases.

FossilOrigin-Name: d670e8bd51c794e2d7ea365ca553c2b74cf5a3a3
2010-03-10 20:06:37 +00:00
drh c92271c549 Fix typo in a comment in the sqliteInt.h. No changes to code.
FossilOrigin-Name: 1716821ddb992fd6d1330604d4f59586bf056b00
2010-03-10 14:06:35 +00:00
141 changed files with 12880 additions and 1543 deletions
+11 -2
View File
@@ -176,7 +176,7 @@ OBJS0 = alter.lo analyze.lo attach.lo auth.lo backup.lo bitvec.lo btmutex.lo \
table.lo tokenize.lo trigger.lo update.lo \
util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbetrace.lo \
walker.lo where.lo utf.lo vtab.lo
wal.lo walker.lo where.lo utf.lo vtab.lo
# Object files for the amalgamation.
#
@@ -276,6 +276,8 @@ SRC = \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/wal.c \
$(TOP)/src/wal.h \
$(TOP)/src/walker.c \
$(TOP)/src/where.c
@@ -339,8 +341,8 @@ TESTSRC2 = \
$(TOP)/src/bitvec.c \
$(TOP)/src/btree.c \
$(TOP)/src/build.c \
$(TOP)/src/date.c \
$(TOP)/src/ctime.c \
$(TOP)/src/date.c \
$(TOP)/src/expr.c \
$(TOP)/src/func.c \
$(TOP)/src/insert.c \
@@ -365,6 +367,8 @@ TESTSRC2 = \
$(TOP)/src/vdbeaux.c \
$(TOP)/src/vdbemem.c \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/wal.c \
$(TOP)/src/wal.h \
$(TOP)/src/where.c \
parse.c
@@ -385,6 +389,7 @@ TESTSRC = \
$(TOP)/src/test_backup.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_config.c \
$(TOP)/src/test_demovfs.c \
$(TOP)/src/test_devsym.c \
$(TOP)/src/test_func.c \
$(TOP)/src/test_hexio.c \
@@ -400,6 +405,7 @@ TESTSRC = \
$(TOP)/src/test_server.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_wsd.c
# Header files used by all library source files.
@@ -742,6 +748,9 @@ vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
vtab.lo: $(TOP)/src/vtab.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
wal.lo: $(TOP)/src/wal.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/wal.c
walker.lo: $(TOP)/src/walker.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/walker.c
+1
View File
@@ -386,6 +386,7 @@ TESTSRC = \
$(TOP)/src/test_server.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_wsd.c \
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
+1 -1
View File
@@ -1 +1 @@
3.6.23.1
3.7.0
Vendored Regular → Executable
+11 -10
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.6.23.1.
# Generated by GNU Autoconf 2.62 for sqlite 3.7.0.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.6.23.1'
PACKAGE_STRING='sqlite 3.6.23.1'
PACKAGE_VERSION='3.7.0'
PACKAGE_STRING='sqlite 3.7.0'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
@@ -1487,7 +1487,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.6.23.1 to adapt to many kinds of systems.
\`configure' configures sqlite 3.7.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1552,7 +1552,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.6.23.1:";;
short | recursive ) echo "Configuration of sqlite 3.7.0:";;
esac
cat <<\_ACEOF
@@ -1670,7 +1670,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.6.23.1
sqlite configure 3.7.0
generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1684,7 +1684,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.6.23.1, which was
It was created by sqlite $as_me 3.7.0, which was
generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@
@@ -13972,7 +13972,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.6.23.1, which was
This file was extended by sqlite $as_me 3.7.0, which was
generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14025,7 +14025,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.6.23.1
sqlite config.status 3.7.0
configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
@@ -14458,7 +14458,8 @@ $debug ||
if test -n "$CONFIG_FILES"; then
ac_cr=' '
ac_cr='
'
ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
ac_cs_awk_cr='\\r'
+76
View File
@@ -0,0 +1,76 @@
*** Throughout this document, a page is deemed to have been synced
automatically as soon as it is written when PRAGMA synchronous=OFF.
Otherwise, the page is not synced until the xSync method of the VFS
is called successfully on the file containing the page.
*** Definition: A page of the database file is said to be "overwriteable" if
one or more of the following are true about the page:
(a) The original content of the page as it was at the beginning of
the transaction has been written into the rollback journal and
synced.
(b) The page was a freelist leaf page at the start of the transaction.
(c) The page number is greater than the largest page that existed in
the database file at the start of the transaction.
(1) A page of the database file is never overwritten unless one of the
following are true:
(a) The page and all other pages on the same sector are overwriteable.
(b) The atomic page write optimization is enabled, and the entire
transaction other than the update of the transaction sequence
number consists of a single page change.
(2) The content of a page written into the rollback journal exactly matches
both the content in the database when the rollback journal was written
and the content in the database at the beginning of the current
transaction.
(3) Writes to the database file are an integer multiple of the page size
in length and are aligned to a page boundary.
(4) Reads from the database file are either aligned on a page boundary and
an integer multiple of the page size in length or are taken from the
first 100 bytes of the database file.
(5) All writes to the database file are synced prior to the rollback journal
being deleted, truncated, or zeroed.
(6) If a master journal file is used, then all writes to the database file
are synced prior to the master journal being deleted.
*** Definition: Two databases (or the same database at two points it time)
are said to be "logically equivalent" if they give the same answer to
all queries. Note in particular the the content of freelist leaf
pages can be changed arbitarily without effecting the logical equivalence
of the database.
(7) At any time, if any subset, including the empty set and the total set,
of the unsynced changes to a rollback journal are removed and the
journal is rolled back, the resulting database file will be logical
equivalent to the database file at the beginning of the transaction.
(8) When a transaction is rolled back, the xTruncate method of the VFS
is called to restore the database file to the same size it was at
the beginning of the transaction. (In some VFSes, the xTruncate
method is a no-op, but that does not change the fact the SQLite will
invoke it.)
(9) Whenever the database file is modified, at least one bit in the range
of bytes from 24 through 39 inclusive will be changed prior to releasing
the EXCLUSIVE lock.
(10) The pattern of bits in bytes 24 through 39 shall not repeat in less
than one billion transactions.
(11) A database file is well-formed at the beginning and at the conclusion
of every transaction.
(12) An EXCLUSIVE lock must be held on the database file before making
any changes to the database file.
(13) A SHARED lock must be held on the database file before reading any
content out of the database file.
+130
View File
@@ -0,0 +1,130 @@
The 5 states of an historical rollback lock as implemented by the
xLock, xUnlock, and xCheckReservedLock methods of the sqlite3_io_methods
objec are:
UNLOCKED
SHARED
RESERVED
PENDING
EXCLUSIVE
The wal-index file has a similar locking hierarchy implemented using
the xShmLock method of the sqlite3_vfs object, but with 7
states. Each connection to a wal-index file must be in one of
the following 7 states:
UNLOCKED
READ
READ_FULL
WRITE
PENDING
CHECKPOINT
RECOVER
These roughly correspond to the 5 states of a rollback lock except
that SHARED is split out into 2 states: READ and READ_FULL and
there is an extra RECOVER state used for wal-index reconstruction.
The meanings of the various wal-index locking states is as follows:
UNLOCKED - The wal-index is not in use.
READ - Some prefix of the wal-index is being read. Additional
wal-index information can be appended at any time. The
newly appended content will be ignored by the holder of
the READ lock.
READ_FULL - The entire wal-index is being read. No new information
can be added to the wal-index. The holder of a READ_FULL
lock promises never to read pages from the database file
that are available anywhere in the wal-index.
WRITE - It is OK to append to the wal-index file and to adjust
the header to indicate the new "last valid frame".
PENDING - Waiting on all READ locks to clear so that a
CHECKPOINT lock can be acquired.
CHECKPOINT - It is OK to write any WAL data into the database file
and zero the last valid frame field of the wal-index
header. The wal-index file itself may not be changed
other than to zero the last valid frame field in the
header.
RECOVER - Held during wal-index recovery. Used to prevent a
race if multiple clients try to recover a wal-index at
the same time.
A particular lock manager implementation may coalesce one or more of
the wal-index locking states, though with a reduction in concurrency.
For example, an implemention might implement only exclusive locking,
in which case all states would be equivalent to CHECKPOINT, meaning that
only one reader or one writer or one checkpointer could be active at a
time. Or, an implementation might combine READ and READ_FULL into
a single state equivalent to READ, meaning that a writer could
coexist with a reader, but no reader or writers could coexist with a
checkpointer.
The lock manager must obey the following rules:
(1) A READ cannot coexist with CHECKPOINT.
(2) A READ_FULL cannot coexist with WRITE.
(3) None of WRITE, PENDING, CHECKPOINT, or RECOVER can coexist.
The SQLite core will obey the next set of rules. These rules are
assertions on the behavior of the SQLite core which might be verified
during testing using an instrumented lock manager.
(5) No part of the wal-index will be read without holding either some
kind of SHM lock or an EXCLUSIVE lock on the original database.
The original database is the file named in the 2nd parameter to
the xShmOpen method.
(6) A holder of a READ_FULL will never read any page of the database
file that is contained anywhere in the wal-index.
(7) No part of the wal-index other than the header will be written nor
will the size of the wal-index grow without holding a WRITE or
an EXCLUSIVE on the original database file.
(8) The wal-index header will not be written without holding one of
WRITE, CHECKPOINT, or RECOVER on the wal-index or an EXCLUSIVE on
the original database files.
(9) A CHECKPOINT or RECOVER must be held on the wal-index, or an
EXCLUSIVE on the original database file, in order to reset the
last valid frame counter in the header of the wal-index back to zero.
(10) A WRITE can only increase the last valid frame pointer in the header.
The SQLite core will only ever send requests for UNLOCK, READ, WRITE,
CHECKPOINT, or RECOVER to the lock manager. The SQLite core will never
request a READ_FULL or PENDING lock though the lock manager may deliver
those locking states in response to READ and CHECKPOINT requests,
respectively, if and only if the requested READ or CHECKPOINT cannot
be delivered.
The following are the allowed lock transitions:
Original-State Request New-State
-------------- ---------- ----------
(11a) UNLOCK READ READ
(11b) UNLOCK READ READ_FULL
(11c) UNLOCK CHECKPOINT PENDING
(11d) UNLOCK CHECKPOINT CHECKPOINT
(11e) READ UNLOCK UNLOCK
(11f) READ WRITE WRITE
(11g) READ RECOVER RECOVER
(11h) READ_FULL UNLOCK UNLOCK
(11i) READ_FULL WRITE WRITE
(11j) READ_FULL RECOVER RECOVER
(11k) WRITE READ READ
(11l) PENDING UNLOCK UNLOCK
(11m) PENDING CHECKPOINT CHECKPOINT
(11n) CHECKPOINT UNLOCK UNLOCK
(11o) RECOVER READ READ
These 15 transitions are all that needs to be supported. The lock
manager implementation can assert that fact. The other 27 possible
transitions among the 7 locking states will never occur.
+138 -72
View File
@@ -48,7 +48,7 @@
** This is similar in concept to how sqlite encodes "varints" but
** the encoding is not the same. SQLite varints are big-endian
** are are limited to 9 bytes in length whereas FTS3 varints are
** little-endian and can be upt to 10 bytes in length (in theory).
** little-endian and can be up to 10 bytes in length (in theory).
**
** Example encodings:
**
@@ -59,26 +59,26 @@
**
**** Document lists ****
** A doclist (document list) holds a docid-sorted list of hits for a
** given term. Doclists hold docids, and can optionally associate
** token positions and offsets with docids. A position is the index
** of a word within the document. The first word of the document has
** a position of 0.
** given term. Doclists hold docids and associated token positions.
** A docid is the unique integer identifier for a single document.
** A position is the index of a word within the document. The first
** word of the document has a position of 0.
**
** FTS3 used to optionally store character offsets using a compile-time
** option. But that functionality is no longer supported.
**
** A DL_POSITIONS_OFFSETS doclist is stored like this:
** A doclist is stored like this:
**
** array {
** varint docid;
** array { (position list for column 0)
** varint position; (delta from previous position plus POS_BASE)
** varint position; (2 more than the delta from previous position)
** }
** array {
** varint POS_COLUMN; (marks start of position list for new column)
** varint column; (index of new column)
** array {
** varint position; (delta from previous position plus POS_BASE)
** varint position; (2 more than the delta from previous position)
** }
** }
** varint POS_END; (marks end of positions for this document.
@@ -90,7 +90,7 @@
** in the same logical place as the position element, and act as sentinals
** ending a position list array. POS_END is 0. POS_COLUMN is 1.
** The positions numbers are not stored literally but rather as two more
** the difference from the prior position, or the just the position plus
** than the difference from the prior position, or the just the position plus
** 2 for the first position. Example:
**
** label: A B C D E F G H I J K
@@ -104,14 +104,14 @@
** 234 at I is the next docid. It has one position 72 (72-2) and then
** terminates with the 0 at K.
**
** A DL_POSITIONS doclist omits the startOffset and endOffset
** information. A DL_DOCIDS doclist omits both the position and
** offset information, becoming an array of varint-encoded docids.
**
** On-disk data is stored as type DL_DEFAULT, so we don't serialize
** the type. Due to how deletion is implemented in the segmentation
** system, on-disk doclists MUST store at least positions.
** A "position-list" is the list of positions for multiple columns for
** a single docid. A "column-list" is the set of positions for a single
** column. Hence, a position-list consists of one or more column-lists,
** a document record consists of a docid followed by a position-list and
** a doclist consists of one or more document records.
**
** A bare doclist omits the position information, becoming an
** array of varint-encoded docids.
**
**** Segment leaf nodes ****
** Segment leaf nodes store terms and doclists, ordered by term. Leaf
@@ -359,8 +359,7 @@ int sqlite3Fts3GetVarint32(const char *p, int *pi){
}
/*
** Return the number of bytes required to store the value passed as the
** first argument in varint form.
** Return the number of bytes required to encode v as a varint
*/
int sqlite3Fts3VarintLen(sqlite3_uint64 v){
int i = 0;
@@ -411,7 +410,7 @@ void sqlite3Fts3Dequote(char *z){
/*
** Read a single varint from the doclist at *pp and advance *pp to point
** to the next element of the varlist. Add the value of the varint
** to the first byte past the end of the varint. Add the value of the varint
** to *pVal.
*/
static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){
@@ -467,7 +466,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
**
** If *pRc is initially non-zero then this routine is a no-op.
*/
void fts3DbExec(
static void fts3DbExec(
int *pRc, /* Success code */
sqlite3 *db, /* Database in which to run SQL */
const char *zFormat, /* Format string for SQL */
@@ -547,6 +546,10 @@ static int fts3DeclareVtab(Fts3Table *p){
** Create the backing store tables (%_content, %_segments and %_segdir)
** required by the FTS3 table passed as the only argument. This is done
** as part of the vtab xCreate() method.
**
** If the p->bHasDocsize boolean is true (indicating that this is an
** FTS4 table, not an FTS3 table) then also create the %_docsize and
** %_stat tables required by FTS4.
*/
static int fts3CreateTables(Fts3Table *p){
int rc = SQLITE_OK; /* Return code */
@@ -639,7 +642,7 @@ static void fts3TableExists(
**
** The argv[] array contains the following:
**
** argv[0] -> module name
** argv[0] -> module name ("fts3" or "fts4")
** argv[1] -> database name
** argv[2] -> table name
** argv[...] -> "column name" and other module argument fields.
@@ -658,12 +661,12 @@ static int fts3InitVtab(
int rc; /* Return code */
int i; /* Iterator variable */
int nByte; /* Size of allocation used for *p */
int iCol;
int nString = 0;
int nCol = 0;
char *zCsr;
int nDb;
int nName;
int iCol; /* Column index */
int nString = 0; /* Bytes required to hold all column names */
int nCol = 0; /* Number of columns in the FTS table */
char *zCsr; /* Space for holding column names */
int nDb; /* Bytes required to hold database name */
int nName; /* Bytes required to hold table name */
const char *zTokenizer = 0; /* Name of tokenizer to use */
sqlite3_tokenizer *pTokenizer = 0; /* Tokenizer for this table */
@@ -893,6 +896,11 @@ static int fulltextClose(sqlite3_vtab_cursor *pCursor){
return SQLITE_OK;
}
/*
** Position the pCsr->pStmt statement so that it is on the row
** of the %_content table that contains the last match. Return
** SQLITE_OK on success.
*/
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
if( pCsr->isRequireSeek ){
pCsr->isRequireSeek = 0;
@@ -919,6 +927,17 @@ static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
}
}
/*
** Advance the cursor to the next row in the %_content table that
** matches the search criteria. For a MATCH search, this will be
** the next row that matches. For a full-table scan, this will be
** simply the next row in the %_content table. For a docid lookup,
** this routine simply sets the EOF flag.
**
** Return SQLITE_OK if nothing goes wrong. SQLITE_OK is returned
** even if we reach end-of-file. The fts3EofMethod() will be called
** subsequently to determine whether or not an EOF was hit.
*/
static int fts3NextMethod(sqlite3_vtab_cursor *pCursor){
int rc = SQLITE_OK; /* Return code */
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
@@ -1055,6 +1074,11 @@ static void fts3PutDeltaVarint(
** start of a position-list. After it returns, *ppPoslist points to the
** first byte after the position-list.
**
** A position list is list of positions (delta encoded) and columns for
** a single document record of a doclist. So, in other words, this
** routine advances *ppPoslist so that it points to the next docid in
** the doclist, or to the first byte past the end of the doclist.
**
** If pp is not NULL, then the contents of the position list are copied
** to *pp. *pp is set to point to the first byte past the last byte copied
** before this function returns.
@@ -1064,17 +1088,20 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
char c = 0;
/* The end of a position list is marked by a zero encoded as an FTS3
** varint. A single 0x00 byte. Except, if the 0x00 byte is preceded by
** varint. A single POS_END (0) byte. Except, if the 0 byte is preceded by
** a byte with the 0x80 bit set, then it is not a varint 0, but the tail
** of some other, multi-byte, value.
**
** The following block moves pEnd to point to the first byte that is not
** The following while-loop moves pEnd to point to the first byte that is not
** immediately preceded by a byte with the 0x80 bit set. Then increments
** pEnd once more so that it points to the byte immediately following the
** last byte in the position-list.
*/
while( *pEnd | c ) c = *pEnd++ & 0x80;
pEnd++;
while( *pEnd | c ){
c = *pEnd++ & 0x80;
testcase( c!=0 && (*pEnd)==0 );
}
pEnd++; /* Advance past the POS_END terminator byte */
if( pp ){
int n = (int)(pEnd - *ppPoslist);
@@ -1086,12 +1113,34 @@ static void fts3PoslistCopy(char **pp, char **ppPoslist){
*ppPoslist = pEnd;
}
/*
** When this function is called, *ppPoslist is assumed to point to the
** start of a column-list. After it returns, *ppPoslist points to the
** to the terminator (POS_COLUMN or POS_END) byte of the column-list.
**
** A column-list is list of delta-encoded positions for a single column
** within a single document within a doclist.
**
** The column-list is terminated either by a POS_COLUMN varint (1) or
** a POS_END varint (0). This routine leaves *ppPoslist pointing to
** the POS_COLUMN or POS_END that terminates the column-list.
**
** If pp is not NULL, then the contents of the column-list are copied
** to *pp. *pp is set to point to the first byte past the last byte copied
** before this function returns. The POS_COLUMN or POS_END terminator
** is not copied into *pp.
*/
static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
char *pEnd = *ppPoslist;
char c = 0;
/* A column-list is terminated by either a 0x01 or 0x00. */
while( 0xFE & (*pEnd | c) ) c = *pEnd++ & 0x80;
/* A column-list is terminated by either a 0x01 or 0x00 byte that is
** not part of a multi-byte varint.
*/
while( 0xFE & (*pEnd | c) ){
c = *pEnd++ & 0x80;
testcase( c!=0 && ((*pEnd)&0xfe)==0 );
}
if( pp ){
int n = (int)(pEnd - *ppPoslist);
char *p = *pp;
@@ -1103,37 +1152,45 @@ static void fts3ColumnlistCopy(char **pp, char **ppPoslist){
}
/*
** Value used to signify the end of an offset-list. This is safe because
** Value used to signify the end of an position-list. This is safe because
** it is not possible to have a document with 2^31 terms.
*/
#define OFFSET_LIST_END 0x7fffffff
#define POSITION_LIST_END 0x7fffffff
/*
** This function is used to help parse offset-lists. When this function is
** called, *pp may point to the start of the next varint in the offset-list
** being parsed, or it may point to 1 byte past the end of the offset-list
** (in which case **pp will be 0x00 or 0x01).
** This function is used to help parse position-lists. When this function is
** called, *pp may point to the start of the next varint in the position-list
** being parsed, or it may point to 1 byte past the end of the position-list
** (in which case **pp will be a terminator bytes POS_END (0) or
** (1)).
**
** If *pp points past the end of the current offset list, set *pi to
** OFFSET_LIST_END and return. Otherwise, read the next varint from *pp,
** If *pp points past the end of the current position-list, set *pi to
** POSITION_LIST_END and return. Otherwise, read the next varint from *pp,
** increment the current value of *pi by the value read, and set *pp to
** point to the next value before returning.
**
** Before calling this routine *pi must be initialized to the value of
** the previous position, or zero if we are reading the first position
** in the position-list. Because positions are delta-encoded, the value
** of the previous position is needed in order to compute the value of
** the next position.
*/
static void fts3ReadNextPos(
char **pp, /* IN/OUT: Pointer into offset-list buffer */
sqlite3_int64 *pi /* IN/OUT: Value read from offset-list */
char **pp, /* IN/OUT: Pointer into position-list buffer */
sqlite3_int64 *pi /* IN/OUT: Value read from position-list */
){
if( **pp&0xFE ){
if( (**pp)&0xFE ){
fts3GetDeltaVarint(pp, pi);
*pi -= 2;
}else{
*pi = OFFSET_LIST_END;
*pi = POSITION_LIST_END;
}
}
/*
** If parameter iCol is not 0, write an 0x01 byte followed by the value of
** iCol encoded as a varint to *pp.
** If parameter iCol is not 0, write an POS_COLUMN (1) byte followed by
** the value of iCol encoded as a varint to *pp. This will start a new
** column list.
**
** Set *pp to point to the byte just after the last byte written before
** returning (do not modify it if iCol==0). Return the total number of bytes
@@ -1151,7 +1208,11 @@ static int fts3PutColNumber(char **pp, int iCol){
}
/*
**
** Compute the union of two position lists. The output written
** into *pp contains all positions of both *pp1 and *pp2 in sorted
** order and with any duplicates removed. All pointers are
** updated appropriately. The caller is responsible for insuring
** that there is enough space in *pp to hold the complete output.
*/
static void fts3PoslistMerge(
char **pp, /* Output buffer */
@@ -1163,32 +1224,33 @@ static void fts3PoslistMerge(
char *p2 = *pp2;
while( *p1 || *p2 ){
int iCol1;
int iCol2;
int iCol1; /* The current column index in pp1 */
int iCol2; /* The current column index in pp2 */
if( *p1==0x01 ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
else if( *p1==0x00 ) iCol1 = OFFSET_LIST_END;
if( *p1==POS_COLUMN ) sqlite3Fts3GetVarint32(&p1[1], &iCol1);
else if( *p1==POS_END ) iCol1 = POSITION_LIST_END;
else iCol1 = 0;
if( *p2==0x01 ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
else if( *p2==0x00 ) iCol2 = OFFSET_LIST_END;
if( *p2==POS_COLUMN ) sqlite3Fts3GetVarint32(&p2[1], &iCol2);
else if( *p2==POS_END ) iCol2 = POSITION_LIST_END;
else iCol2 = 0;
if( iCol1==iCol2 ){
sqlite3_int64 i1 = 0;
sqlite3_int64 i2 = 0;
sqlite3_int64 i1 = 0; /* Last position from pp1 */
sqlite3_int64 i2 = 0; /* Last position from pp2 */
sqlite3_int64 iPrev = 0;
int n = fts3PutColNumber(&p, iCol1);
p1 += n;
p2 += n;
/* At this point, both p1 and p2 point to the start of offset-lists.
** An offset-list is a list of non-negative delta-encoded varints, each
** incremented by 2 before being stored. Each list is terminated by a 0
** or 1 value (0x00 or 0x01). The following block merges the two lists
/* At this point, both p1 and p2 point to the start of column-lists
** for the same column (the column with index iCol1 and iCol2).
** A column-list is a list of non-negative delta-encoded varints, each
** incremented by 2 before being stored. Each list is terminated by a
** POS_END (0) or POS_COLUMN (1). The following block merges the two lists
** and writes the results to buffer p. p is left pointing to the byte
** after the list written. No terminator (0x00 or 0x01) is written to
** the output.
** after the list written. No terminator (POS_END or POS_COLUMN) is
** written to the output.
*/
fts3GetDeltaVarint(&p1, &i1);
fts3GetDeltaVarint(&p2, &i2);
@@ -1203,7 +1265,7 @@ static void fts3PoslistMerge(
}else{
fts3ReadNextPos(&p2, &i2);
}
}while( i1!=OFFSET_LIST_END || i2!=OFFSET_LIST_END );
}while( i1!=POSITION_LIST_END || i2!=POSITION_LIST_END );
}else if( iCol1<iCol2 ){
p1 += fts3PutColNumber(&p, iCol1);
fts3ColumnlistCopy(&p, &p1);
@@ -1213,7 +1275,7 @@ static void fts3PoslistMerge(
}
}
*p++ = '\0';
*p++ = POS_END;
*pp = p;
*pp1 = p1 + 1;
*pp2 = p2 + 1;
@@ -1236,11 +1298,11 @@ static int fts3PoslistPhraseMerge(
int iCol1 = 0;
int iCol2 = 0;
assert( *p1!=0 && *p2!=0 );
if( *p1==0x01 ){
if( *p1==POS_COLUMN ){
p1++;
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
}
if( *p2==0x01 ){
if( *p2==POS_COLUMN ){
p2++;
p2 += sqlite3Fts3GetVarint32(p2, &iCol2);
}
@@ -1253,11 +1315,12 @@ static int fts3PoslistPhraseMerge(
sqlite3_int64 iPos2 = 0;
if( pp && iCol1 ){
*p++ = 0x01;
*p++ = POS_COLUMN;
p += sqlite3Fts3PutVarint(p, iCol1);
}
assert( *p1!=0x00 && *p2!=0x00 && *p1!=0x01 && *p2!=0x01 );
assert( *p1!=POS_END && *p1!=POS_COLUMN );
assert( *p2!=POS_END && *p2!=POS_COLUMN );
fts3GetDeltaVarint(&p1, &iPos1); iPos1 -= 2;
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
@@ -1509,6 +1572,7 @@ static int fts3DoclistMerge(
default: assert( mergetype==MERGE_POS_NEAR || mergetype==MERGE_NEAR ); {
char *aTmp = 0;
char **ppPos = 0;
if( mergetype==MERGE_POS_NEAR ){
ppPos = &p;
aTmp = sqlite3_malloc(2*(n1+n2+1));
@@ -1613,9 +1677,9 @@ static int fts3TermSelectCb(
**
** The returned doclist may be in one of two formats, depending on the
** value of parameter isReqPos. If isReqPos is zero, then the doclist is
** a sorted list of delta-compressed docids. If isReqPos is non-zero,
** then the returned list is in the same format as is stored in the
** database without the found length specifier at the start of on-disk
** a sorted list of delta-compressed docids (a bare doclist). If isReqPos
** is non-zero, then the returned list is in the same format as is stored
** in the database without the found length specifier at the start of on-disk
** doclists.
*/
static int fts3TermSelect(
@@ -1875,7 +1939,9 @@ int sqlite3Fts3ExprNearTrim(Fts3Expr *pLeft, Fts3Expr *pRight, int nNear){
/*
** Evaluate the full-text expression pExpr against fts3 table pTab. Store
** the resulting doclist in *paOut and *pnOut.
** the resulting doclist in *paOut and *pnOut. This routine mallocs for
** the space needed to store the output. The caller is responsible for
** freeing the space when it has finished.
*/
static int evalFts3Expr(
Fts3Table *p, /* Virtual table handle */
+14
View File
@@ -53,6 +53,20 @@
*/
#define FTS3_VARINT_MAX 10
/*
** The testcase() macro is only used by the amalgamation. If undefined,
** make it a no-op.
*/
#ifndef testcase
# define testcase(X)
#endif
/*
** Terminator values for position-lists and column-lists.
*/
#define POS_COLUMN (1) /* Column-list terminator */
#define POS_END (0) /* Position-list terminator */
/*
** This section provides definitions to allow the
** FTS3 extension to be compiled outside of the
+1 -1
View File
@@ -571,7 +571,7 @@ static int fts3StringAppend(
** is no way for fts3BestSnippet() to know whether or not the document
** actually contains terms that follow the final highlighted term.
*/
int fts3SnippetShift(
static int fts3SnippetShift(
Fts3Table *pTab, /* FTS3 table snippet comes from */
int nSnippet, /* Number of tokens desired for snippet */
const char *zDoc, /* Document text to extract snippet from */
+1
View File
@@ -2483,6 +2483,7 @@ static int rtreeUpdate(
}
rc = sqlite3_reset(pRtree->pReadRowid);
}
*pRowid = cell.iRowid;
if( rc==SQLITE_OK ){
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
+17
View File
@@ -399,4 +399,21 @@ do_test rtree-10.1 {
catchsql { CREATE VIRTUAL TABLE t7 USING rtree(index, x1, y1, x2, y2) }
} {1 {near "index": syntax error}}
#-------------------------------------------------------------------------
# Test last_insert_rowid().
#
do_test rtree-11.1 {
execsql {
CREATE VIRTUAL TABLE t8 USING rtree(idx, x1, x2, y1, y2);
INSERT INTO t8 VALUES(1, 1.0, 1.0, 2.0, 2.0);
SELECT last_insert_rowid();
}
} {1}
do_test rtree-11.2 {
execsql {
INSERT INTO t8 VALUES(NULL, 1.0, 1.0, 2.0, 2.0);
SELECT last_insert_rowid();
}
} {2}
finish_test
Regular → Executable
View File
+7 -3
View File
@@ -66,7 +66,7 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
table.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbetrace.o \
walker.o where.o utf.o vtab.o
wal.o walker.o where.o utf.o vtab.o
@@ -158,6 +158,8 @@ SRC = \
$(TOP)/src/vdbetrace.c \
$(TOP)/src/vdbeInt.h \
$(TOP)/src/vtab.c \
$(TOP)/src/wal.c \
$(TOP)/src/wal.h \
$(TOP)/src/walker.c \
$(TOP)/src/where.c
@@ -231,6 +233,7 @@ TESTSRC = \
$(TOP)/src/test_backup.c \
$(TOP)/src/test_btree.c \
$(TOP)/src/test_config.c \
$(TOP)/src/test_demovfs.c \
$(TOP)/src/test_devsym.c \
$(TOP)/src/test_func.c \
$(TOP)/src/test_hexio.c \
@@ -246,6 +249,7 @@ TESTSRC = \
$(TOP)/src/test_server.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_wsd.c
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
@@ -254,8 +258,8 @@ TESTSRC = \
TESTSRC2 = \
$(TOP)/src/attach.c $(TOP)/src/backup.c $(TOP)/src/btree.c \
$(TOP)/src/build.c $(TOP)/src/date.c \
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/mem5.c \
$(TOP)/src/os.c \
$(TOP)/src/expr.c $(TOP)/src/func.c $(TOP)/src/insert.c $(TOP)/src/wal.c \
$(TOP)/src/mem5.c $(TOP)/src/os.c \
$(TOP)/src/os_os2.c $(TOP)/src/os_unix.c $(TOP)/src/os_win.c \
$(TOP)/src/pager.c $(TOP)/src/pragma.c $(TOP)/src/prepare.c \
$(TOP)/src/printf.c $(TOP)/src/random.c $(TOP)/src/pcache.c \
+147 -125
View File
@@ -1,14 +1,14 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Update\sthe\sversion\snumber\sto\s3.6.23.1.
D 2010-03-26T22:28:06
C Change\sthe\sxShmSize()\simplementation\sin\sos_unix.c\sso\sthat\sit\swill\sonly\nincrease\sand\snever\sdecrease\sthe\ssize\sof\sa\sshared-memory\ssegment.
D 2010-05-13T08:33:36
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 4f2f967b7e58a35bb74fb7ec8ae90e0f4ca7868b
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F Makefile.vxworks ab005d301296c40e021ccd0133ce49ca811e319f
F Makefile.vxworks accd27bfc55cfe3aa48a58c7b9cc9c5fb225a6de
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 09d2dfb6a4a47d07b3b2091e349eedef78fb0f77
F VERSION 4dce4379514b12d6bc5c30f7d1f64582ccb4f412
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/2005osaward.gif 0d1851b2a7c1c9d0ccce545f3e14bca42d7fd248
@@ -22,10 +22,12 @@ F art/src_logo.gif 9341ef09f0e53cd44c0c9b6fc3c16f7f3d6c2ad9
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 868fdb48c028421a203470e15c69ada15b9ba673
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 17dee87ba9b797ea22940dc0fb5b08147bfb246a
F configure 009ceb10a7bd768b6460b7b8782eb639063c8899 x
F configure.ac 14740970ddb674d92a9f5da89083dff1179014ff
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538
F doc/pager-invariants.txt 870107036470d7c419e93768676fae2f8749cf9e
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
F ext/async/README.txt 0c541f418b14b415212264cbaaf51c924ec62e5b
F ext/async/sqlite3async.c 676066c2a111a8b3107aeb59bdbbbf335c348f4a
@@ -59,15 +61,15 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 2bb2045d1412184e9eea71eb151b159168be5131
F ext/fts3/fts3.c 20c55bed37307a2cd590387d33a9c8127b354ab4
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h df812ef35f1b47a44ec68a44ec0c2a769c973d85
F ext/fts3/fts3Int.h 70528ba8c33991699f96ecc64112122833cdbdb5
F ext/fts3/fts3_expr.c f4ff02ebe854e97ac03ff00b38b728a9ab57fd4b
F ext/fts3/fts3_hash.c 3c8f6387a4a7f5305588b203fa7c887d753e1f1c
F ext/fts3/fts3_hash.h 8331fb2206c609f9fc4c4735b9ab5ad6137c88ec
F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
F ext/fts3/fts3_porter.c 7546e4503e286a67fd4f2a82159620e3e9c7a1bc
F ext/fts3/fts3_snippet.c 538bd27a76e465cb4ef6bfcb5479d897e4d5a536
F ext/fts3/fts3_snippet.c bc582c38e194b48818da862f9e6f293cc44e29ee
F ext/fts3/fts3_tokenizer.c 1a49ee3d79cbf0b9386250370d9cbfe4bb89c8ff
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
F ext/fts3/fts3_tokenizer1.c b6d86d1d750787db5c168c73da4e87670ed890a1
@@ -77,9 +79,9 @@ F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33
F ext/icu/icu.c 850e9a36567bbcce6bd85a4b68243cad8e3c2de2
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c a354f6be11a91706680936fdf77b4588f0b34dbe
F ext/rtree/rtree.c c7a18311f2d6ae9a42838e9c04b9e670483b4feb
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test f72885ed80a329d6bd7991043016d74b51edf2c5
F ext/rtree/rtree1.test 51bb0cd0405970501e63258401ae5ad235a4f468
F ext/rtree/rtree2.test 7b665c44d25e51b3098068d983a39902b2e2d7a1
F ext/rtree/rtree3.test dece988c363368af8c11862995c762071894918f
F ext/rtree/rtree4.test 94fdd570ab5bc47244d87d4590023be43ac786bd
@@ -90,98 +92,98 @@ F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/tkt3363.test 2bf324f7908084a5f463de3109db9c6e607feb1b
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk a36a05a481afcc00388c4d6d4db0e12cacb546e3
F main.mk b39182f15fd980b86aceb7e4b9a1ba88abd75e2d
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
F mkopcodec.awk 3fb9bf077053c968451f4dd03d11661ac373f9d1
F mkopcodeh.awk 29b84656502eee5f444c3147f331ee686956ab0e
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F publish.sh c74b6c2b6b63435aa1b4b43b1396dfebfae84095
F publish.sh 313c5b2425f2cf5e547db7549a9796acc4508f22
F publish_osx.sh 2ad2ee7d50632dff99949edc9c162dbb052f7534
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c e6f4d11b1c0b23642fc46bac9abe0753c4294e05
F src/analyze.c 92a65a5a402898a52b03695c7f0cd383724d711f
F src/attach.c 7abe1607c2054585377cdba3c219e8572f84ca5e
F src/alter.c a9ff6f14b3935502537e90194b66c7bc79bed317
F src/analyze.c 8dfd781ac326496746ecdfc3e099250ed5d79be5
F src/attach.c 7f1f760bacd9c5b6cbf6fbc3ceb159ed19ee910a
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c b293534bc2df23c57668a585b17ee7faaaef0939
F src/backup.c de9809091b3b99f69e37261c133f7f8b19f6eca6
F src/bitvec.c 06ad2c36a9c3819c0b9cbffec7b15f58d5d834e0
F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff
F src/btree.c 0d6e44d664b1775b269ea7e6f66fdffcfc32ceb3
F src/btree.h 0e193b7e90f1d78b79c79474040e3d66a553a4fa
F src/btreeInt.h 71ed5e7f009caf17b7dc304350b3cb64b5970135
F src/btree.c d0414a5f09b0cacb64bd60b91c5a3720585925aa
F src/btree.h dd83041eda10c17daf023257c1fc883b5f71f85a
F src/btreeInt.h b0c87f6725b06a0aa194a6d25d54b16ce9d6e291
F src/build.c 11100b66fb97638d2d874c1d34d8db90650bb1d7
F src/callback.c 908f3e0172c3d4058f4ca0acd42c637c52e9669f
F src/callback.c 01843bdf4b0420fd28046525d150fcd9802931a9
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c ceb247eb31620bba66a94c3f697db489a1652353
F src/date.c 485a4409a384310e6d93fd1104a9d0a8658becd9
F src/ctime.c 51553a859994d01d8bf3500747f66a890c459774
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
F src/delete.c 610dc008e88a9599f905f5cbe9577ac9c36e0581
F src/expr.c 6baed2a0448d494233d9c0a610eea018ab386a32
F src/expr.c 110e5eddc8c2b02f2d1b4a5afccf0ff9f7b69ef1
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e2116672a6bd610dc888e27df292ebc7999c9bb0
F src/func.c 5dca069d98eca0ff70c9a8fb8ab9e1d6467187b5
F src/func.c 0c28599430856631216b6c0131c51c89bf516026
F src/global.c 5a9c1e3c93213ca574786ac1caa976ce8f709105
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 76d6b44a9f9050134fd81205f4b792cbdac7c925
F src/insert.c 3a9567687f6b84ab9a41448e3d2ce20424f4743c
F src/journal.c b0ea6b70b532961118ab70301c00a33089f9315c
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 1c7a61ce1281041f437333f366a96aa0d29bb581
F src/main.c 7d89bb6dcc6993a8d32f4f22dae3e57c50a41399
F src/malloc.c 5fa175797f982b178eaf38afba9c588a866be729
F src/main.c cc62a14dd4a4e4f95ea21e762c87da14fe72e63c
F src/malloc.c a08f16d134f0bfab6b20c3cd142ebf3e58235a6a
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 89d4ea8d5cdd55635cbaa48ad53132af6294cbb2
F src/mem2.c ee752297650632935218dcf3b20c5ed5899cb4b5
F src/mem2.c 2ee7bdacda8299b5a91cff9f7ee3e46573195c38
F src/mem3.c 9b237d911ba9904142a804be727cc6664873f8a3
F src/mem5.c eb7a5cb98915dd7a086fa415ce3a5a0f20d0acff
F src/memjournal.c 5bfc2f33c914946e2f77ed3f882aff14dfc9355d
F src/mutex.c 581a272e09098040ca3ef543cb5f3d643eff7d50
F src/memjournal.c f3be374af30588de297dcf678925b2a4758e4135
F src/mutex.c e2358d8f9a9021ab0bba4d511bb701e471e6e5f6
F src/mutex.h 6fde601e55fa6c3fae768783c439797ab84c87c6
F src/mutex_noop.c 5f58eaa31f2d742cb8957a747f7887ae98f16053
F src/mutex_noop.c 10ae943d26ba86ea92319f72adbb501a89c563e0
F src/mutex_os2.c 20477db50cf3817c2f1cd3eb61e5c177e50231db
F src/mutex_unix.c 04a25238abce7e3d06b358dcf706e26624270809
F src/mutex_w32.c 4cc201c1bfd11d1562810554ff5500e735559d7e
F src/notify.c f799bbda67ab6619b36b0a24153b49518874a203
F src/os.c 8bc63cf91e9802e2b807198e54e50227fa889306
F src/os.h 534b082c3cb349ad05fa6fa0b06087e022af282c
F src/os_common.h 240c88b163b02c21a9f21f87d49678a0aa21ff30
F src/os_os2.c 75a8c7b9a00a2cf1a65f9fa4afbc27d46634bb2f
F src/os_unix.c 148d2f625db3727250c0b880481ae7630b6d0eb0
F src/os_win.c 1c7453c2df4dab26d90ff6f91272aea18bcf7053
F src/pager.c 1915e3ec1a2157d0c29086b7fc0c936a2d97029e
F src/pager.h 1b32faf2e578ac3e7bcf9c9d11217128261c5c54
F src/notify.c cbfa66a836da3a51567209636e6a94059c137930
F src/os.c c0a5dfce2a214dacb679425632d04f8a2021f364
F src/os.h 8a7e2456237ecf3a2e55b02f9fe6091f1ad36902
F src/os_common.h 0d6ee583b6ee3185eb9d951f890c6dd03021a08d
F src/os_os2.c 8ad77a418630d7dee91d1bb04f79c2096301d3a0
F src/os_unix.c a65eb0c527306fbf8d5818c068cccb4179e2c187
F src/os_win.c a8fc01d8483be472e495793c01064fd87e56a5c1
F src/pager.c 1e163a82ae8405433dca559831caa06aafbba3b0
F src/pager.h 76466c3a5af56943537f68b1f16567101a0cd1d0
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
F src/pcache.c 4956b41d6ba913f7a8a56fbf32be78caed0e45c2
F src/pcache.c ace8f6a5ecd4711cc66a1b23053be7109bd437cf
F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
F src/pcache1.c 2bb2261190b42a348038f5b1c285c8cef415fcc8
F src/pragma.c 56d95f76154a5f873c32eae485bb625f3c70be46
F src/prepare.c 18292e5f365655cd5c5693e09508e90668f7d547
F src/pcache1.c 6dc1871ce8ead9187161c370a58cd06c84221f76
F src/pragma.c 423865323a4074f1e0d4ab02af0be014653e8863
F src/prepare.c fd1398cb1da54385ba5bd68d93928f10d10a1d9c
F src/printf.c 5f5b65a83e63f2096a541a340722a509fa0240a7
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c a1648d98e869937b29f4f697461fe4d60f220a7b
F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 4113ef360430ed4e7533690ef46d06c20204adce
F src/shell.c c40427c7245535a04a9cb4a417b6cc05c022e6a4
F src/sqlite.h.in 08a2d9a278ff0dfd65055a7ec9c599f7ae1a3c18
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
F src/sqlite.h.in a86bb87f5c9e97ed286a70d515d6c19de031f382
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F src/sqliteInt.h 6873f7f4c24fcdceece8777f2a1cbec049df77a0
F src/sqliteLimit.h 3afab2291762b5d09ae20c18feb8e9fa935a60a6
F src/status.c d329385a2cba3ea49d9d68af0ad84b22d46b4f40
F src/sqliteInt.h 9819b45610abeca390176243a9a31758c1f0ac7a
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
F src/status.c 4df6fe7dce2d256130b905847c6c60055882bdbe
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c bad6570a005b234ea670b9f7b48256da19a032d3
F src/test1.c aa9b1e10e834330e7759afb639420117e2422ded
F src/test2.c b6b43413d495addd039a88b87d65c839f86b18cb
F src/tclsqlite.c 6bc5fbde634b9cb42b3d29d674fa6cd0c22c0881
F src/test1.c ff95ca772d1df51618f9f1ef7ea432cdf851f97b
F src/test2.c 31f1b9d076b4774a22d2605d0af1f34e14a9a7bd
F src/test3.c 4c21700c73a890a47fc685c1097bfb661346ac94
F src/test4.c ad03bb987ddedce928f4258c1e7fa4109a73497d
F src/test5.c cc55900118fa4add8ec9cf69fc4225a4662f76b1
F src/test6.c a8ece4284d0e34477f349ac05655db73c48e0926
F src/test6.c d00c3930e2d22a9dc84415b1a2ead2ca4ab430ae
F src/test7.c 3f2d63e4ccf97f8c2cf1a7fa0a3c8e2e2a354e6e
F src/test8.c f959db9a22d882013b64c92753fa793b2ce3bdea
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
@@ -189,47 +191,51 @@ F src/test_async.c c1656facbaf43cb2e71b62621e5b9eb080e2621c
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c 5844274bf6cec4af3e6461fb3e2d349082635e81
F src/test_devsym.c de3c9af2bb9a8b1e44525c449e4ec3f88e3d4110
F src/test_config.c 6210f501d358bde619ae761f06f123529c6ba24f
F src/test_demovfs.c da81a5f7785bb352bda7911c332a983ec4f17f27
F src/test_devsym.c 136869028132c3dc34fe920a9fda716f391227f4
F src/test_func.c 13b582345fb1185a93e46c53310fae8547dcce20
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
F src/test_intarray.h 489edb9068bb926583445cb02589344961054207
F src/test_journal.c adc0ce3840ed19b49feb1d583b2212f560ef7866
F src/test_journal.c 51da4dd6118ee843349592fde29429fab84a6243
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c f777d15df756bea0e98271932464ac5d882e66fe
F src/test_malloc.c 2842c922b8e8d992aba722214952204ca025b411
F src/test_mutex.c ce06b59aca168cd8c520b77159a24352a7469bd3
F src/test_onefile.c 06da7e085dce42924cf062b91763dd4bb84c6101
F src/test_osinst.c 90fb03d396f39956897dfb4bd0e62c6711db1cca
F src/test_onefile.c df4d7858b5cd1dffe92d36ec9dbad11f0037ffd1
F src/test_osinst.c f5d1a4ee8b80fc58d1430c56146de748584013a9
F src/test_pcache.c 7bf828972ac0d2403f5cfa4cd14da41f8ebe73d8
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c 00fed80690ae7f1525483a35861511c48bc579f2
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
F src/test_vfs.c 3601f9b6d46cb6daf0697d60c76bf8e18b90b123
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
F src/trigger.c 340c9eca0fb24b1197468d96ba059f867c9834c7
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
F src/update.c c0dc6b75ad28b76b619042d934f337b02acee208
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
F src/vacuum.c b1d542c8919d4d11119f78069e1906a1ad07e0ee
F src/vdbe.c 8acca6dab2505e9650f6f014ada6ef30570cba99
F src/vacuum.c b17355fc10cef0875626932ec2f1fa1deb0daa48
F src/vdbe.c 8c6301a7dd844d2d6370ebd46f4e2d0cf449c2de
F src/vdbe.h 471f6a3dcec4817ca33596fe7f6654d56c0e75f3
F src/vdbeInt.h ae1e6ba0dd3fb4a886898d2829d748be701b01f8
F src/vdbeapi.c 74c25680046a116b24b95393914d3669c23305dc
F src/vdbeaux.c 0f352f63be78138bd94275aa3c8361e760ecc639
F src/vdbeInt.h 19ebc8c2a2e938340051ee65af3f377fb99102d1
F src/vdbeapi.c dc3138f10afbc95ed3c21dd25abb154504b1db9d
F src/vdbeaux.c 69f5887979504b464b8dda565816541adab3e2df
F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 606adf51cd6d4ba51a8c6dccede06a6f7b0dd72d
F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
F src/wal.c 3806c5ed7047debc408665b3576f17bab05b2be6
F src/wal.h 434f76f51225bb614e43ccb6bd2341541ba6a06e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 399ea4c090284c9d16f76d685b9b44e8b9b4442b
F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 14165b3e32715b700b5f0cbf8f6e3833dda0be45
F test/alter.test 645b2e8d23c9936f9494af9d2fa7f8351a248c6e
F test/alter2.test d0133bfa7a0a24aa84c034051410b95217d24a35
F test/alter.test 15f9224868b290d6bf7a63f31437f31aee070636
F test/alter2.test 0266160d61b0f7156b7e7a9905dbf85ebe067c63
F test/alter3.test 25b95a136708f22b87184fa6a4309eea03d65153
F test/alter4.test 9386ffd1e9c7245f43eca412b2058d747509cc1f
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
@@ -239,7 +245,7 @@ F test/analyze3.test 506203875258ffd8ffa879b9c3c5432022d2b6d8
F test/async.test 8c75d31b8330f8b70cf2571b014d4476a063efdb
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
F test/async4.test aafa6328c559d3e4bb587de770cbdecfca06f0da
F test/async4.test 166cc07057ff6f908fe42dcffaa8ca732c757acb
F test/async5.test f3592d79c84d6e83a5f50d3fd500445f7d97dfdf
F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81
F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437
@@ -249,16 +255,17 @@ F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46
F test/autoindex1.test ffb06a246e2c1f89cfbe3d93eca513c9e78d4063
F test/autovacuum.test 25f891bc343a8bf5d9229e2e9ddab9f31a9ab5ec
F test/autovacuum_ioerr2.test 598b0663074d3673a9c1bc9a16e80971313bafe6
F test/avtrans.test 1e901d8102706b63534dbd2bdd4d8f16c4082650
F test/backup.test 3549ea8f541a08205c0eb813b21e81ea8301f6ed
F test/avtrans.test 7a26ffc6a355b7fbff2a082f56180ede863b126c
F test/backup.test 5f7f66d067e695a6040be3295a5abc289f823838
F test/backup2.test 159419073d9769fdb1780ed7e5b391a046f898d5
F test/backup_ioerr.test 1f012e692f42c0442ae652443258f70e9f20fa38
F test/backup_malloc.test 1e063c6d75143d0d6e0ae77971dd690070369387
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
F test/between.test 16b1776c6323faadb097a52d673e8e3d8be7d070
F test/bigfile.test b746a34ce0e2039994b45fea8b7fbfa78f594cdf
F test/bigfile.test 1e12ce56e59fc41ace231009599506c22b031fbb
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
@@ -274,7 +281,7 @@ F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test 3ff445c445742a7b6b9ba6e1d62a25263f9424b9
F test/capi2.test 172c717ed101e78e0798dd21b9896a22366f35b4
F test/capi2.test 00032d7504b9c14f1b36331670c5e7b0f73e3c5d
F test/capi3.test 168e2cd66c58c510955b0f299750e4de73b8d952
F test/capi3b.test 664eb55318132f292f2c436f90906f578cad6b97
F test/capi3c.test 493385107dcedfaf4f2b1c3738c8c1fa00362006
@@ -285,7 +292,7 @@ F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
F test/collate1.test e3eaa48c21e150814be1a7b852d2a8af24458d04
F test/collate2.test 04cebe4a033be319d6ddbb3bbc69464e01700b49
F test/collate3.test d28d2cfab2c3a3d4628ae4b2b7afc9965daa3b4c
F test/collate4.test 4545554388daaa604e5b3def3aa2f7ed6d56e8da
F test/collate4.test 3d3f123f83fd8ccda6f48d617e44e661b9870c7d
F test/collate5.test fe0f43c4740d7b71b959cac668d19e42f2e06e4d
F test/collate6.test 8be65a182abaac8011a622131486dafb8076e907
F test/collate7.test fac8db7aac3978466c04ae892cc74dcf2bc031aa
@@ -296,7 +303,7 @@ F test/colmeta.test 087c42997754b8c648819832241daf724f813322
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
F test/conflict.test 0ed68b11f22721052d880ee80bd528a0e0828236
F test/corrupt.test 0d346c9fe064ca71281685a8a732fcc83461bb99
F test/corrupt2.test a571e30ea4e82318f319a24b6cc55935ce862079
F test/corrupt2.test 576122d756feda40e63ef1c1ff6c4720a927d126
F test/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32
F test/corrupt4.test acdb01afaedf529004b70e55de1a6f5a05ae7fff
F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
@@ -304,11 +311,11 @@ F test/corrupt6.test e69b877d478224deab7b66844566258cecacd25e
F test/corrupt7.test 1eb2214f29474fa6b155aa3da8a7d46bf52089e1
F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51
F test/corrupt9.test 4aa1cb1ef091cb0e13e89a819c72911631b5176a
F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff
F test/corruptB.test 66b4544104dd03d0f33ea69ddac3fa4a682cd3c2
F test/corruptA.test 38b4f81c16099f6d8fa8b37e188fde76b8243994
F test/corruptB.test d88b500f7994cb2eb9646410c263111e9831f889
F test/corruptC.test 691ed070baef5e1345939caadf270a52837a5064
F test/corruptD.test 3ae6e2dc6e2226c6935a8a40d4b5ee3eba75f8c0
F test/corruptE.test dbf66cae4c0e977ca9625a9114cdd01df8967bef
F test/corruptE.test 34de490791060d749c933aef3970839df3f63ea9
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
@@ -323,6 +330,7 @@ F test/createtab.test 199cf68f44e5d9e87a0b8afc7130fdeb4def3272
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test f5040beef89c1b2bdb6a9edb7358a519213ff80c
F test/date.test 0b8473ed9ab6fd4283b4a01f035e1067762ba734
F test/dbstatus.test 838447a0ecca1232675b025c0a518a9ef0f8057e
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test f7629d9eb245dfca170169cc5c7a735dec34aeb4
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@@ -333,7 +341,7 @@ F test/descidx3.test 3394ad4d089335cac743c36a14129d6d931c316f
F test/diskfull.test 0cede7ef9d8f415d9d3944005c76be7589bb5ebb
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_fkey.test 6721a741c6499b3ab7e5385923233343c8f1ad05
F test/e_fts3.test 5adb033fae6e07002d11f4a7c8f8e8ff9f31e8ec
F test/e_fts3.test 75bb0aee26384ef586165e21018a17f7cd843469
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
@@ -345,7 +353,7 @@ F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test e71f5baf9bb42cdba4700d73cba6f4d82fd6b925
F test/fkey2.test d5e065ede294ab52affe2116d54dc85a09301354
F test/fkey3.test 42f88d6048d8dc079e2a8cf7baad1cc1483a7620
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
@@ -384,7 +392,7 @@ F test/fts2q.test b2fbbe038b7a31a52a6079b215e71226d8c6a682
F test/fts2r.test b154c30b63061d8725e320fba1a39e2201cadd5e
F test/fts2token.test d8070b241a15ff13592a9ae4a8b7c171af6f445a
F test/fts3.test ae0433b09b12def08105640e57693726c4949338
F test/fts3_common.tcl 1d887ded06dac9b993cfb175618df7f70c796de2
F test/fts3_common.tcl 4d8eec9db565fed9098f45c378f28e1657802011
F test/fts3aa.test 5327d4c1d9b6c61021696746cc9a6cdc5bf159c0
F test/fts3ab.test 09aeaa162aee6513d9ff336b6932211008b9d1f9
F test/fts3ac.test 636ed7486043055d4f126a0e385f2d5a82ebbf63
@@ -410,8 +418,8 @@ F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
F test/fts3malloc.test 059592c4f37ccd30138bbf8e3e5b7982cb5c8f2e
F test/fts3near.test 2e318ee434d32babd27c167142e2b94ddbab4844
F test/fts3query.test 154fe4b015fd61af523ee083570a134f508f5be7
F test/fts3rnd.test 2f5761db9dd92f6fe09d08976ac658ef521846ed
F test/fts3query.test 2468caf7938dbc3be2e049524320ce4faf2227b3
F test/fts3rnd.test 707533ce943f490443ce5e696236bb1675a37635
F test/fts3snippet.test 9f9a4a7e396c5d8ce2898be65ebabc429555430f
F test/fts4aa.test eadf85621c0a113d4c7ad3ccbf8441130e007b8f
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
@@ -421,7 +429,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
F test/fuzz_malloc.test 4eca9d345f06d5b0b0105f7a2ef9e7f22658827b
F test/hook.test c9c992f2914977072a71e98df3bfcad1f47737c9
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
F test/icu.test 1fc0ff9a3bafc80abf679b11afc0f8a3ce995abd
F test/in.test d49419c6df515852f477fa513f3317181d46bc92
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
@@ -437,7 +445,7 @@ F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 727d55dceb9a4ec36675057bb5becfc265e28ca6
F test/indexedby.test 946ca2628a521f4ced0520421a0788345abaf3dc
F test/init.test 3f9e97948cf2335c08a5e3edc3df3a26cdaa76f2
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
@@ -446,7 +454,7 @@ F test/insert5.test 1f93cbe9742110119133d7e8e3ccfe6d7c249766
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1
F test/intpkey.test 537669fd535f62632ca64828e435b9e54e8d677f
F test/io.test e7bd58edb4e2131a8ecd81b4b00af3ee5c79d464
F test/io.test 1b895d6774491895cbc75659969f07ca01860c88
F test/ioerr.test 390785ec65f10aa58a82b048ee12e9052d783fa8
F test/ioerr2.test 1b56cb80d5b0726ee3ba325ca175734541e32955
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
@@ -459,7 +467,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
F test/jrnlmode.test a765844f22b3f6d72d78a68d5decd26c64bb859c
F test/jrnlmode.test a7407c0f193696f0ef303c663916c89e3bc4605d
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
@@ -471,12 +479,13 @@ F test/limit.test 2db7b3b34fb925b8e847d583d2eb67531d0ce67e
F test/loadext.test 0393ce12d9616aa87597dd0ec88181de181f6db0
F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca
F test/lock.test 842e80b6be816c79525a20b098cca066989feed7
F test/lock2.test 7bb642551df59b3de135291d62ee82409420181e
F test/lock2.test 64ba8f1c7709abf91287d564984a6b8c5209e755
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
F test/lock4.test f4f36271aa5ae1da449646bf43c7341f6b2b4c4e
F test/lock5.test 6b1f78f09ad1522843dad571b76b321e6f439bf7
F test/lock6.test 862aa71e97b288d6b3f92ba3313f51bd0b003776
F test/lock7.test 64006c84c1c616657e237c7ad6532b765611cf64
F test/lock_common.tcl bbc4e15ee5334cc4d01fcac08d7c9de7d8906e55
F test/lookaside.test 1dd350dc6dff015c47c07fcc5a727a72fc5bae02
F test/main.test 2be2352ac77ac5b238c6337a5469aeeef57677e6
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
@@ -500,7 +509,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test e3ea401904d010cb7c1e4b2ee8803f4a9f5b999d
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 984baeb6c6b185e798827d1187d426acc2bc4962
F test/malloc_common.tcl f95c4d3459877e64c2d856b8a9c39210f9968ddf
F test/manydb.test b3d3bc4c25657e7f68d157f031eb4db7b3df0d3c
F test/memdb.test 0825155b2290e900264daaaf0334b6dfe69ea498
F test/memleak.test d2d2a1ff7105d32dc3fdf691458cf6cba58c7217
@@ -509,7 +518,7 @@ F test/memsubsys2.test 72a731225997ad5e8df89fdbeae9224616b6aecc
F test/minmax.test 722d80816f7e096bf2c04f4111f1a6c1ba65453d
F test/minmax2.test 33504c01a03bd99226144e4b03f7631a274d66e0
F test/minmax3.test a38686c33b07d595e98a2fc6d3aa84a5e886a972
F test/misc1.test 1b89c02c4a33b49dee4cd1d20d161aaaba719075
F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b
F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd
F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6
F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de
@@ -529,33 +538,33 @@ F test/pageropt.test 3ee6578891baaca967f0bd349e4abfa736229e1a
F test/pagesize.test 76aa9f23ecb0741a4ed9d2e16c5fa82671f28efb
F test/pcache.test eebc4420b37cb07733ae9b6e99c9da7c40dd6d58
F test/pcache2.test 0d85f2ab6963aee28c671d4c71bec038c00a1d16
F test/permutations.test 91928573ca2db2c88dbc50ab34e4a585d912b580
F test/pragma.test 5aeb48a442dba3c3e8e38773b121371814ab3b17
F test/permutations.test d5872f8d7f854e0e78d127a7e148c58b2703c8a8
F test/pragma.test 6960f9efbce476f70ba9ee2171daf5042f9e3d8a
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 05970cde31b1a9f54bd75af60597be75a5c54fea
F test/progress.test 5b075c3c790c7b2a61419bc199db87aaf48b8301
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/quick.test d6591e74f3ac19da7fd076845f06dca48fd43cff
F test/quick.test 6f202befe1cfae0b63df96b3120a8022ab11f574
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/randexpr1.tcl 40dec52119ed3a2b8b2a773bce24b63a3a746459
F test/randexpr1.test 1084050991e9ba22c1c10edd8d84673b501cc25a
F test/rdonly.test bd054831f8a3078e765a0657e247182486f0cb47
F test/rdonly.test c243623b26c311faab2aee311a26af372e123a65
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/rollback.test 73355ad4492ff9a3a31e61c7e5eb5e01a1de94ca
F test/rowhash.test 97f56043ba11f0679920416c0cdbc72e5272267b
F test/rowid.test e58e0acef38b527ed1b0b70d3ada588f804af287
F test/rtree.test 55466a200af3591946c5da77ad5dbfbc1e5e05f9
F test/savepoint.test f2ede4b643ad87ead36c041c72d774a1f5c8a564
F test/savepoint2.test 427c8b20f43d3edf17a290c6788ae9e2703ac51c
F test/savepoint.test 14f78c2c2538764850b38446957048113cc24f75
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
F test/savepoint6.test 2df1d093e59e78d688c64eb20e0457aaea7d08f9
F test/savepoint6.test bdc653c5c08328c84a74471b5b23fd483b919dfe
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/securedel.test 328d2921c0ca49bdd3352e516b0377fc07143254
F test/select1.test f67ca2dfc05df41c7b86eb32ca409b427a5f43b0
F test/select2.test 9735da20ccd41e42bf2b4c19fd939141b591adae
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054
F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17
F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535
@@ -565,7 +574,7 @@ F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
F test/select9.test b4007b15396cb7ba2615cab31e1973b572e43210
F test/selectA.test 06d1032fa9009314c95394f2ca2e60d9f7ae8532
F test/selectB.test f305cc6660804cb239aab4e2f26b0e288b59958b
F test/selectC.test 07a45610c8b3bd878943004fd23f4cc0682bd4c0
F test/selectC.test 33bb5673a8141df193c6fd56e6de7fea38b8d2ee
F test/server1.test f5b790d4c0498179151ca8a7715a65a7802c859c
F test/shared.test 3b448dc0f7a9356e641894ed81c27599f39d809d
F test/shared2.test d6ba4ca1827ea36a1ac23a99e3c36eeac9165450
@@ -594,13 +603,13 @@ F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/sync.test ded6b39d8d8ca3c0c5518516c6371b3316d3e3a3
F test/table.test bf102a5669c4db7a41330802f24a4a81a4204f83
F test/table.test 04ba066432430657712d167ebf28080fe878d305
F test/tableapi.test 7262a8cbaa9965d429f1cbd2747edc185fa56516
F test/tclsqlite.test bf4227eb236a4c097aa7974a2bf7d3225acf34be
F test/tclsqlite.test 013133fa83128569c6fb8a7a48dc7c4507e6ff1c
F test/tempdb.test 1bf52da28a9c24e29717362a87722dff08feb72b
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
F test/tester.tcl e1f581c7a2648a0aaa51135c4d2e7be68f4b9292
F test/tester.tcl f6b79073ad3a18439ad3a643f812e1d0c47dbb7b
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
@@ -608,9 +617,11 @@ F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f
F test/thread005.test bf5c374ca65dd89fd56c8fe511ccfb46875bda5e
F test/thread1.test 862dd006d189e8b0946935db17399dcac2f8ef91
F test/thread2.test 6e0997f7beabb6a7e471bd18740ed04805c785f4
F test/thread_common.tcl b65e6b1d1d90dc885e10ad080896c6c56eef0819
F test/thread_common.tcl 0b07423d29ddb73d4bacbac69268c8d37b6cc5d2
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
F test/threadtest2.c ace893054fa134af3fc8d6e7cfecddb8e3acefb9
F test/tkt-02a8e81d44.test 58494de77be2cf249228ada3f313fa399821c6ab
F test/tkt-26ff0c2d1e.test 888324e751512972c6e0d1a09df740d8f5aaf660
F test/tkt-2ea2425d34.test 1cf13e6f75d149b3209a0cb32927a82d3d79fb28
F test/tkt-31338dca7e.test 5741cd48de500347a437ba1be58c8335e83c5a5e
F test/tkt-3fe897352e.test 10de1a67bd5c66b238a4c96abe55531b37bb4f00
@@ -618,6 +629,8 @@ F test/tkt-4a03edc4c8.test 2865e4edbc075b954daa82f8da7cc973033ec76e
F test/tkt-5ee23731f.test 3581260f2a71e51db94e1506ba6b0f7311d002a9
F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
F test/tkt-9d68c883.test 4251ef9fa08158e50b28a682e56124457a59d048
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
F test/tkt-f777251dc7a.test 6f24c053bc5cdb7e1e19be9a72c8887cf41d5e87
F test/tkt1435.test f8c52c41de6e5ca02f1845f3a46e18e25cadac00
@@ -706,7 +719,7 @@ F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
F test/trans.test d887cb07630dc39879a322d958ad8b006137485c
F test/trans.test f19bd2c8b5ccc89295454a42b35319b1381b9a3d
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
F test/trans3.test d728abaa318ca364dc370e06576aa7e5fbed7e97
F test/trigger1.test 2e18561f85e448bb633c9c9de792e9bbf7b2dd3e
@@ -718,9 +731,9 @@ F test/trigger6.test 0e411654f122552da6590f0b4e6f781048a4a9b9
F test/trigger7.test 72feaf8dbc52cea84de0c3e6ce7559ff19c479af
F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
F test/trigger9.test 5b0789f1c5c4600961f8e68511b825b87be53e31
F test/triggerA.test 0718ad2d9bfef27c7af00e636df79bee6b988da7
F test/triggerA.test eaf11a29db2a11967d2d4b49d37f92bce598194e
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test 4083c64d80854d271bad211268a08985f3d61cbd
F test/triggerC.test cac41fe31adc1abb9fa08532762fc2b4f662ab03
F test/triggerD.test c6add3817351451e419f6ff9e9a259b02b6e2de7
F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
@@ -728,7 +741,7 @@ F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vacuum.test 68e39b2228b4b772166debef4a82accf6ddd32f3
F test/vacuum.test 15ae6784e70428b8db64e95c92d84b19e507b719
F test/vacuum2.test ec57f21d394b7b72249b11f8e4b5d487bab56539
F test/vacuum3.test f39ad1428347c5808cd2da7578c470f186a4d0ce
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
@@ -752,14 +765,23 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test 7a100918c45872fa19cfb4413299b9afb08727b6
F test/wal2.test 2eba114ff58f0688278ad45249625af89a0bc9fa
F test/walbak.test a0e45187c7d8928df035dfea29b99b016b21ca3c
F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
F test/walfault.test 98df47444944a6db2161eed5cef71d6c00bcb8c3
F test/walhook.test c3314e30baf074dd087d52d21ea6f1d09138b0a0
F test/walmode.test 6ca9d710cc9f6545b913abcded6d6b0b15641048
F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
F test/walthread.test 1a8c55cd9e3272ba0caa028d8f0ead04989a3378
F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
F test/where2.test 45eacc126aabb37959a387aa83e59ce1f1f03820
F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
F test/where3.test aa44a9b29e8c9f3d7bb94a3bb3a95b31627d520d
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test fdd58ab9dec9f97679e65d4414bf5e07d725d79f
F test/where8.test 2bb8ea44b745fcc93db150fac9ce33d12e499760
F test/where7.test a0a92b8ce48d9c027fbdd7b764c7de1e1213575a
F test/where8.test a6c740fd286d7883e274e17b6230a9d672a7ab1f
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test be19e1a92f80985c1a121b4678bf7d2123eaa623
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
@@ -775,7 +797,7 @@ F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
F tool/mkkeywordhash.c d2e6b4a5965e23afb80fbe74bb54648cd371f309
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c.tcl 4c6924c7e877defa8f9a12ef1e6867de614acf3f
F tool/mksqlite3c.tcl aff0d53f0e84cf919922c0d02e767bdf5eeafb90
F tool/mksqlite3h.tcl eb100dce83f24b501b325b340f8b5eb8e5106b3b
F tool/mksqlite3internalh.tcl 7b43894e21bcb1bb39e11547ce7e38a063357e87
F tool/omittest.tcl 27d6f6e3b1e95aeb26a1c140e6eb57771c6d794a
@@ -784,7 +806,7 @@ F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/shell1.test ef08a3e738b9fee4fc228920956950bc35db0575
F tool/shell2.test 8f51f61c13b88618e71c17439fe0847c2421c5d1
F tool/shell3.test ff663e83100670a295d473515c12beb8103a78b6
F tool/showdb.c 8ab8b3b53884312aafb7ef60982e255a6c31d238
F tool/showdb.c 12fbece85695e3a61bdb4f7607b61f264120c4b6
F tool/showjournal.c ec3b171be148656827c4949fbfb8ab4370822f87
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
@@ -795,14 +817,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P b1f342a6643829020beef542a0700d90822e6467
R 590a011d9441875bded2c173c371f1c1
P 3cab9022457ce50f82c5822d8ba6c04a3a85cb6a
R 8a7d44076bf0e05c11800be3998eddd6
U drh
Z f7171db765620a4ccff85bc2ced22202
Z 3a36caf9fe5b6632b303e603e184218b
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFLrTT6oxKgR168RlERArP2AJ0UeA3bKxomgH1prR7M+4tHuMlN7wCfXBZE
Jr7IGDFSJ/vsM6VpeiKkkf4=
=diSA
iD8DBQFL67ljoxKgR168RlERAvKRAJ9jAZ2qvV6Q9GpsBE6wLhS3nq7pbACfcnYP
hXJABDPCTP9dztwWLTfVSAc=
=rTx0
-----END PGP SIGNATURE-----
+1 -1
View File
@@ -1 +1 @@
b078b588d617e07886ad156e9f54ade6d823568e
149d2ae4a6fe2f86822f286d2a7092c51bec7ebb
+14 -13
View File
@@ -34,19 +34,6 @@ gzip sqlite3-$VERS.bin
chmod 644 sqlite3-$VERS.bin.gz
mv sqlite3-$VERS.bin.gz doc
# Build a source archive useful for windows.
#
make target_source
cd tsrc
echo '***** BUILDING preprocessed source archives'
rm fts[12]* icu*
rm -f ../doc/sqlite-source-$VERSW.zip
zip ../doc/sqlite-source-$VERSW.zip *
cd ..
cp tsrc/sqlite3.h tsrc/sqlite3ext.h .
pwd
zip doc/sqlite-amalgamation-$VERSW.zip sqlite3.c sqlite3.h sqlite3ext.h
# Build the sqlite.so and tclsqlite.so shared libraries
# under Linux
#
@@ -87,6 +74,20 @@ i386-mingw32msvc-gcc -Os $OPTS -Itsrc -I$TCLDIR sqlite3.c tsrc/shell.c \
-o sqlite3.exe
zip doc/sqlite-$VERSW.zip sqlite3.exe
# Build a source archive useful for windows.
#
make target_source
cd tsrc
echo '***** BUILDING preprocessed source archives'
rm fts[12]* icu*
rm -f ../doc/sqlite-source-$VERSW.zip
zip ../doc/sqlite-source-$VERSW.zip *
cd ..
cp tsrc/sqlite3.h tsrc/sqlite3ext.h .
cp tsrc/shell.c .
pwd
zip doc/sqlite-amalgamation-$VERSW.zip sqlite3.c sqlite3.h sqlite3ext.h shell.c sqlite3.def
# Construct a tarball of the source tree
#
echo '***** BUILDING source archive'
+21 -8
View File
@@ -226,17 +226,23 @@ static void renameTriggerFunc(
/*
** Register built-in functions used to help implement ALTER TABLE
*/
void sqlite3AlterFunctions(sqlite3 *db){
sqlite3CreateFunc(db, "sqlite_rename_table", 2, SQLITE_UTF8, 0,
renameTableFunc, 0, 0);
void sqlite3AlterFunctions(void){
static SQLITE_WSD FuncDef aAlterTableFuncs[] = {
FUNCTION(sqlite_rename_table, 2, 0, 0, renameTableFunc),
#ifndef SQLITE_OMIT_TRIGGER
sqlite3CreateFunc(db, "sqlite_rename_trigger", 2, SQLITE_UTF8, 0,
renameTriggerFunc, 0, 0);
FUNCTION(sqlite_rename_trigger, 2, 0, 0, renameTriggerFunc),
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
sqlite3CreateFunc(db, "sqlite_rename_parent", 3, SQLITE_UTF8, 0,
renameParentFunc, 0, 0);
FUNCTION(sqlite_rename_parent, 3, 0, 0, renameParentFunc),
#endif
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAlterTableFuncs);
for(i=0; i<ArraySize(aAlterTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
}
/*
@@ -380,7 +386,9 @@ void sqlite3AlterRenameTable(
char *zWhere = 0; /* Where clause to locate temp triggers */
#endif
VTable *pVTab = 0; /* Non-zero if this is a v-tab with an xRename() */
int savedDbFlags; /* Saved value of db->flags */
savedDbFlags = db->flags;
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
assert( pSrc->nSrc==1 );
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -389,6 +397,7 @@ void sqlite3AlterRenameTable(
if( !pTab ) goto exit_rename_table;
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
zDb = db->aDb[iDb].zName;
db->flags |= SQLITE_PreferBuiltin;
/* Get a NULL terminated version of the new table name. */
zName = sqlite3NameFromToken(db, pName);
@@ -556,6 +565,7 @@ void sqlite3AlterRenameTable(
exit_rename_table:
sqlite3SrcListDelete(db, pSrc);
sqlite3DbFree(db, zName);
db->flags = savedDbFlags;
}
@@ -675,9 +685,11 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zCol = sqlite3DbStrNDup(db, (char*)pColDef->z, pColDef->n);
if( zCol ){
char *zEnd = &zCol[pColDef->n-1];
int savedDbFlags = db->flags;
while( zEnd>zCol && (*zEnd==';' || sqlite3Isspace(*zEnd)) ){
*zEnd-- = '\0';
}
db->flags |= SQLITE_PreferBuiltin;
sqlite3NestedParse(pParse,
"UPDATE \"%w\".%s SET "
"sql = substr(sql,1,%d) || ', ' || %Q || substr(sql,%d) "
@@ -686,6 +698,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
zTab
);
sqlite3DbFree(db, zCol);
db->flags = savedDbFlags;
}
/* If the default value of the new column is NULL, then set the file
+9 -5
View File
@@ -618,12 +618,16 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
n = 24;
}
pSample->nByte = (u8)n;
pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
if( pSample->u.z ){
memcpy(pSample->u.z, z, n);
if( n < 1){
pSample->u.z = 0;
}else{
db->mallocFailed = 1;
break;
pSample->u.z = sqlite3DbMallocRaw(dbMem, n);
if( pSample->u.z ){
memcpy(pSample->u.z, z, n);
}else{
db->mallocFailed = 1;
break;
}
}
}
}
+13 -1
View File
@@ -143,7 +143,8 @@ static void attachFunc(
}
pPager = sqlite3BtreePager(aNew->pBt);
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
sqlite3PagerJournalMode(pPager, db->dfltJournalMode);
/* journal_mode set by the OP_JournalMode opcode that will following
** the OP_Function opcode that invoked this function. */
sqlite3BtreeSecureDelete(aNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
}
@@ -339,6 +340,17 @@ static void codeAttach(
sqlite3VdbeChangeP5(v, (u8)(pFunc->nArg));
sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF);
if( type==SQLITE_ATTACH ){
/* On an attach, also set the journal mode. Note that
** sqlite3VdbeUsesBtree() is not call here since the iDb index
** will be out of range prior to the new database being attached.
** The OP_JournalMode opcode will all sqlite3VdbeUsesBtree() for us.
*/
sqlite3VdbeAddOp3(v, OP_JournalMode, db->nDb, regArgs+3,
db->dfltJournalMode);
sqlite3VdbeChangeP5(v, 1);
}
/* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this
** statement only). For DETACH, set it to false (expire all existing
** statements).
+30 -18
View File
@@ -217,7 +217,7 @@ static int backupOnePage(sqlite3_backup *p, Pgno iSrcPg, const u8 *zSrcData){
/* Catch the case where the destination is an in-memory database and the
** page sizes of the source and destination differ.
*/
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(sqlite3BtreePager(p->pDest)) ){
if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
rc = SQLITE_READONLY;
}
@@ -287,6 +287,9 @@ static void attachBackupObject(sqlite3_backup *p){
*/
int sqlite3_backup_step(sqlite3_backup *p, int nPage){
int rc;
int destMode; /* Destination journal mode */
int pgszSrc = 0; /* Source page size */
int pgszDest = 0; /* Destination page size */
sqlite3_mutex_enter(p->pSrcDb->mutex);
sqlite3BtreeEnter(p->pSrc);
@@ -327,13 +330,22 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
rc = sqlite3BtreeBeginTrans(p->pSrc, 0);
bCloseTrans = 1;
}
/* Do not allow backup if the destination database is in WAL mode
** and the page sizes are different between source and destination */
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
destMode = sqlite3PagerJournalMode(sqlite3BtreePager(p->pDest),
PAGER_JOURNALMODE_QUERY);
if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
rc = SQLITE_READONLY;
}
/* Now that there is a read-lock on the source database, query the
** source pager for the number of pages in the database.
*/
if( rc==SQLITE_OK ){
rc = sqlite3PagerPagecount(pSrcPager, &nSrcPage);
}
nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc);
assert( nSrcPage>=0 );
for(ii=0; (nPage<0 || ii<nPage) && p->iNext<=(Pgno)nSrcPage && !rc; ii++){
const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
@@ -364,8 +376,6 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( rc==SQLITE_DONE
&& (rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1))==SQLITE_OK
){
const int nSrcPagesize = sqlite3BtreeGetPageSize(p->pSrc);
const int nDestPagesize = sqlite3BtreeGetPageSize(p->pDest);
int nDestTruncate;
if( p->pDestDb ){
@@ -384,18 +394,20 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** journalled by PagerCommitPhaseOne() before they are destroyed
** by the file truncation.
*/
if( nSrcPagesize<nDestPagesize ){
int ratio = nDestPagesize/nSrcPagesize;
assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) );
assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) );
if( pgszSrc<pgszDest ){
int ratio = pgszDest/pgszSrc;
nDestTruncate = (nSrcPage+ratio-1)/ratio;
if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
nDestTruncate--;
}
}else{
nDestTruncate = nSrcPage * (nSrcPagesize/nDestPagesize);
nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
}
sqlite3PagerTruncateImage(pDestPager, nDestTruncate);
if( nSrcPagesize<nDestPagesize ){
if( pgszSrc<pgszDest ){
/* If the source page-size is smaller than the destination page-size,
** two extra things may need to happen:
**
@@ -405,31 +417,31 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
** pending-byte page in the source database may need to be
** copied into the destination database.
*/
const i64 iSize = (i64)nSrcPagesize * (i64)nSrcPage;
const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
assert( pFile );
assert( (i64)nDestTruncate*(i64)nDestPagesize >= iSize || (
assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+nDestPagesize
&& iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
));
if( SQLITE_OK==(rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 1))
&& SQLITE_OK==(rc = backupTruncateFile(pFile, iSize))
&& SQLITE_OK==(rc = sqlite3PagerSync(pDestPager))
){
i64 iOff;
i64 iEnd = MIN(PENDING_BYTE + nDestPagesize, iSize);
i64 iEnd = MIN(PENDING_BYTE + pgszDest, iSize);
for(
iOff=PENDING_BYTE+nSrcPagesize;
iOff=PENDING_BYTE+pgszSrc;
rc==SQLITE_OK && iOff<iEnd;
iOff+=nSrcPagesize
iOff+=pgszSrc
){
PgHdr *pSrcPg = 0;
const Pgno iSrcPg = (Pgno)((iOff/nSrcPagesize)+1);
const Pgno iSrcPg = (Pgno)((iOff/pgszSrc)+1);
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg);
if( rc==SQLITE_OK ){
u8 *zData = sqlite3PagerGetData(pSrcPg);
rc = sqlite3OsWrite(pFile, zData, nSrcPagesize, iOff);
rc = sqlite3OsWrite(pFile, zData, pgszSrc, iOff);
}
sqlite3PagerUnref(pSrcPg);
}
+154 -68
View File
@@ -516,11 +516,8 @@ static void invalidateIncrblobCursors(
static int btreeSetHasContent(BtShared *pBt, Pgno pgno){
int rc = SQLITE_OK;
if( !pBt->pHasContent ){
int nPage = 100;
sqlite3PagerPagecount(pBt->pPager, &nPage);
/* If sqlite3PagerPagecount() fails there is no harm because the
** nPage variable is unchanged from its default value of 100 */
pBt->pHasContent = sqlite3BitvecCreate((u32)nPage);
assert( pgno<=pBt->nPage );
pBt->pHasContent = sqlite3BitvecCreate(pBt->nPage);
if( !pBt->pHasContent ){
rc = SQLITE_NOMEM;
}
@@ -1563,13 +1560,13 @@ static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){
** Return the size of the database file in pages. If there is any kind of
** error, return ((unsigned int)-1).
*/
static Pgno pagerPagecount(BtShared *pBt){
int nPage = -1;
int rc;
assert( pBt->pPage1 );
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
assert( rc==SQLITE_OK || nPage==-1 );
return (Pgno)nPage;
static Pgno btreePagecount(BtShared *pBt){
return pBt->nPage;
}
u32 sqlite3BtreeLastPage(Btree *p){
assert( sqlite3BtreeHoldsMutex(p) );
assert( ((p->pBt->nPage)&0x8000000)==0 );
return (int)btreePagecount(p->pBt);
}
/*
@@ -1586,9 +1583,11 @@ static int getAndInitPage(
MemPage **ppPage /* Write the page pointer here */
){
int rc;
TESTONLY( Pgno iLastPg = pagerPagecount(pBt); )
assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno<=0 || pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
rc = btreeGetPage(pBt, pgno, ppPage, 0);
if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage);
@@ -1596,15 +1595,6 @@ static int getAndInitPage(
releasePage(*ppPage);
}
}
/* If the requested page number was either 0 or greater than the page
** number of the last page in the database, this function should return
** SQLITE_CORRUPT or some other error (i.e. SQLITE_FULL). Check that this
** is the case. */
assert( (pgno>0 && pgno<=iLastPg) || rc!=SQLITE_OK );
testcase( pgno==0 );
testcase( pgno==iLastPg );
return rc;
}
@@ -2240,9 +2230,11 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
int rc;
MemPage *pPage1;
int nPage;
int rc; /* Result code from subfunctions */
MemPage *pPage1; /* Page 1 of the database file */
int nPage; /* Number of pages in the database */
int nPageFile = 0; /* Number of pages in the database file */
int nPageHeader; /* Number of pages in the database according to hdr */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( pBt->pPage1==0 );
@@ -2254,10 +2246,14 @@ static int lockBtree(BtShared *pBt){
/* Do some checking to help insure the file we opened really is
** a valid database file.
*/
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
if( rc!=SQLITE_OK ){
nPage = nPageHeader = get4byte(28+(u8*)pPage1->aData);
if( (rc = sqlite3PagerPagecount(pBt->pPager, &nPageFile))!=SQLITE_OK ){;
goto page1_init_failed;
}else if( nPage>0 ){
}
if( nPage==0 ){
nPage = nPageFile;
}
if( nPage>0 ){
int pageSize;
int usableSize;
u8 *page1 = pPage1->aData;
@@ -2265,12 +2261,42 @@ static int lockBtree(BtShared *pBt){
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
}
#ifdef SQLITE_OMIT_WAL
if( page1[18]>1 ){
pBt->readOnly = 1;
}
if( page1[19]>1 ){
goto page1_init_failed;
}
#else
if( page1[18]>2 ){
pBt->readOnly = 1;
}
if( page1[19]>2 ){
goto page1_init_failed;
}
/* If the write version is set to 2, this database should be accessed
** in WAL mode. If the log is not already open, open it now. Then
** return SQLITE_OK and return without populating BtShared.pPage1.
** The caller detects this and calls this function again. This is
** required as the version of page 1 currently in the page1 buffer
** may not be the latest version - there may be a newer one in the log
** file.
*/
if( page1[19]==2 && pBt->doNotUseWAL==0 ){
int isOpen = 0;
rc = sqlite3PagerOpenWal(pBt->pPager, &isOpen);
if( rc!=SQLITE_OK ){
goto page1_init_failed;
}else if( isOpen==0 ){
releasePage(pPage1);
return SQLITE_OK;
}
rc = SQLITE_NOTADB;
}
#endif
/* The maximum embedded fraction must be exactly 25%. And the minimum
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
@@ -2303,6 +2329,10 @@ static int lockBtree(BtShared *pBt){
pageSize-usableSize);
return rc;
}
if( nPageHeader>nPageFile ){
rc = SQLITE_CORRUPT_BKPT;
goto page1_init_failed;
}
if( usableSize<480 ){
goto page1_init_failed;
}
@@ -2333,6 +2363,7 @@ static int lockBtree(BtShared *pBt){
pBt->minLeaf = (pBt->usableSize-12)*32/255 - 23;
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
pBt->nPage = nPage;
return SQLITE_OK;
page1_init_failed:
@@ -2370,12 +2401,10 @@ static int newDatabase(BtShared *pBt){
MemPage *pP1;
unsigned char *data;
int rc;
int nPage;
assert( sqlite3_mutex_held(pBt->mutex) );
rc = sqlite3PagerPagecount(pBt->pPager, &nPage);
if( rc!=SQLITE_OK || nPage>0 ){
return rc;
if( pBt->nPage>0 ){
return SQLITE_OK;
}
pP1 = pBt->pPage1;
assert( pP1!=0 );
@@ -2401,6 +2430,8 @@ static int newDatabase(BtShared *pBt){
put4byte(&data[36 + 4*4], pBt->autoVacuum);
put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
pBt->nPage = 1;
data[31] = 1;
return SQLITE_OK;
}
@@ -2490,6 +2521,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK);
if( SQLITE_OK!=rc ) goto trans_begun;
pBt->initiallyEmpty = pBt->nPage==0;
do {
/* Call lockBtree() until either pBt->pPage1 is populated or
** lockBtree() returns something other than SQLITE_OK. lockBtree()
@@ -2769,12 +2801,12 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
*/
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
Pgno nFreeList; /* Number of pages still on the free-list */
int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( iLastPg>nFin );
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
int rc;
u8 eType;
Pgno iPtrPage;
@@ -2850,7 +2882,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
MemPage *pPg;
int rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
rc = btreeGetPage(pBt, iLastPg, &pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -2863,6 +2895,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
iLastPg--;
}
sqlite3PagerTruncateImage(pBt->pPager, iLastPg);
pBt->nPage = iLastPg;
}
return SQLITE_OK;
}
@@ -2885,7 +2918,11 @@ int sqlite3BtreeIncrVacuum(Btree *p){
rc = SQLITE_DONE;
}else{
invalidateAllOverflowCache(pBt);
rc = incrVacuumStep(pBt, 0, pagerPagecount(pBt));
rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
}
}
sqlite3BtreeLeave(p);
return rc;
@@ -2916,7 +2953,7 @@ static int autoVacuumCommit(BtShared *pBt){
int nEntry; /* Number of entries on one ptrmap page */
Pgno nOrig; /* Database size before freeing */
nOrig = pagerPagecount(pBt);
nOrig = btreePagecount(pBt);
if( PTRMAP_ISPAGE(pBt, nOrig) || nOrig==PENDING_BYTE_PAGE(pBt) ){
/* It is not possible to create a database for which the final page
** is either a pointer-map page or the pending-byte page. If one
@@ -2941,11 +2978,12 @@ static int autoVacuumCommit(BtShared *pBt){
rc = incrVacuumStep(pBt, nFin, iFree);
}
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
rc = SQLITE_OK;
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
put4byte(&pBt->pPage1->aData[28], nFin);
sqlite3PagerTruncateImage(pBt->pPager, nFin);
pBt->nPage = nFin;
}
if( rc!=SQLITE_OK ){
sqlite3PagerRollback(pPager);
@@ -3195,6 +3233,11 @@ int sqlite3BtreeRollback(Btree *p){
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
testcase( pBt->nPage!=nPage );
pBt->nPage = nPage;
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -3232,17 +3275,13 @@ int sqlite3BtreeBeginStmt(Btree *p, int iStatement){
assert( pBt->readOnly==0 );
assert( iStatement>0 );
assert( iStatement>p->db->nSavepoint );
if( NEVER(p->inTrans!=TRANS_WRITE || pBt->readOnly) ){
rc = SQLITE_INTERNAL;
}else{
assert( pBt->inTransaction==TRANS_WRITE );
/* At the pager level, a statement transaction is a savepoint with
** an index greater than all savepoints created explicitly using
** SQL statements. It is illegal to open, release or rollback any
** such savepoints while the statement transaction savepoint is active.
*/
rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
}
assert( pBt->inTransaction==TRANS_WRITE );
/* At the pager level, a statement transaction is a savepoint with
** an index greater than all savepoints created explicitly using
** SQL statements. It is illegal to open, release or rollback any
** such savepoints while the statement transaction savepoint is active.
*/
rc = sqlite3PagerOpenSavepoint(pBt->pPager, iStatement);
sqlite3BtreeLeave(p);
return rc;
}
@@ -3268,7 +3307,12 @@ int sqlite3BtreeSavepoint(Btree *p, int op, int iSavepoint){
sqlite3BtreeEnter(p);
rc = sqlite3PagerSavepoint(pBt->pPager, op, iSavepoint);
if( rc==SQLITE_OK ){
if( iSavepoint<0 && pBt->initiallyEmpty ) pBt->nPage = 0;
rc = newDatabase(pBt);
pBt->nPage = get4byte(28 + pBt->pPage1->aData);
if( pBt->nPage==0 ){
sqlite3PagerPagecount(pBt->pPager, (int*)&pBt->nPage);
}
}
sqlite3BtreeLeave(p);
}
@@ -3334,7 +3378,7 @@ static int btreeCursor(
if( NEVER(wrFlag && pBt->readOnly) ){
return SQLITE_READONLY;
}
if( iTable==1 && pagerPagecount(pBt)==0 ){
if( iTable==1 && btreePagecount(pBt)==0 ){
return SQLITE_EMPTY;
}
@@ -3605,7 +3649,7 @@ static int getOverflowPage(
iGuess++;
}
if( iGuess<=pagerPagecount(pBt) ){
if( iGuess<=btreePagecount(pBt) ){
rc = ptrmapGet(pBt, iGuess, &eType, &pgno);
if( rc==SQLITE_OK && eType==PTRMAP_OVERFLOW2 && pgno==ovfl ){
next = iGuess;
@@ -4637,7 +4681,7 @@ static int allocateBtreePage(
assert( sqlite3_mutex_held(pBt->mutex) );
pPage1 = pBt->pPage1;
mxPage = pagerPagecount(pBt);
mxPage = btreePagecount(pBt);
n = get4byte(&pPage1->aData[36]);
testcase( n==mxPage-1 );
if( n>=mxPage ){
@@ -4833,35 +4877,35 @@ static int allocateBtreePage(
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
int nPage = pagerPagecount(pBt);
*pPgno = nPage + 1;
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
(*pPgno)++;
}
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc ) return rc;
pBt->nPage++;
if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ) pBt->nPage++;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, pBt->nPage) ){
/* If *pPgno refers to a pointer-map page, allocate two new pages
** at the end of the file instead of one. The first allocated page
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", *pPgno));
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, &pPg, 0);
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, pBt->nPage, &pPg, 1);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
}
if( rc ) return rc;
(*pPgno)++;
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){ (*pPgno)++; }
pBt->nPage++;
if( pBt->nPage==PENDING_BYTE_PAGE(pBt) ){ pBt->nPage++; }
}
#endif
put4byte(28 + (u8*)pBt->pPage1->aData, pBt->nPage);
*pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, ppPage, 0);
rc = btreeGetPage(pBt, *pPgno, ppPage, 1);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -5051,7 +5095,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
while( nOvfl-- ){
Pgno iNext = 0;
MemPage *pOvfl = 0;
if( ovflPgno<2 || ovflPgno>pagerPagecount(pBt) ){
if( ovflPgno<2 || ovflPgno>btreePagecount(pBt) ){
/* 0 is not a legal page number and page 1 cannot be an
** overflow page. Therefore if ovflPgno<2 or past the end of the
** file the database must be corrupt. */
@@ -6883,8 +6927,14 @@ static int btreeCreateTable(Btree *p, int *piTable, int flags){
releasePage(pRoot);
return rc;
}
/* When the new root page was allocated, page 1 was made writable in
** order either to increase the database filesize, or to decrement the
** freelist count. Hence, the sqlite3BtreeUpdateMeta() call cannot fail.
*/
assert( sqlite3PagerIswriteable(pBt->pPage1->pDbPage) );
rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot);
if( rc ){
if( NEVER(rc) ){
releasePage(pRoot);
return rc;
}
@@ -6924,7 +6974,7 @@ static int clearDatabasePage(
int i;
assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno>pagerPagecount(pBt) ){
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -7675,7 +7725,7 @@ char *sqlite3BtreeIntegrityCheck(
nRef = sqlite3PagerRefcount(pBt->pPager);
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
sCheck.nPage = pagerPagecount(sCheck.pBt);
sCheck.nPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sCheck.nErr = 0;
sCheck.mallocFailed = 0;
@@ -7943,3 +7993,39 @@ void sqlite3BtreeCacheOverflow(BtCursor *pCur){
pCur->isIncrblobHandle = 1;
}
#endif
/*
** Set both the "read version" (single byte at byte offset 18) and
** "write version" (single byte at byte offset 19) fields in the database
** header to iVersion.
*/
int sqlite3BtreeSetVersion(Btree *pBtree, int iVersion){
BtShared *pBt = pBtree->pBt;
int rc; /* Return code */
assert( pBtree->inTrans==TRANS_NONE );
assert( iVersion==1 || iVersion==2 );
/* If setting the version fields to 1, do not automatically open the
** WAL connection, even if the version fields are currently set to 2.
*/
pBt->doNotUseWAL = (iVersion==1);
rc = sqlite3BtreeBeginTrans(pBtree, 0);
if( rc==SQLITE_OK ){
u8 *aData = pBt->pPage1->aData;
if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
rc = sqlite3BtreeBeginTrans(pBtree, 2);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc==SQLITE_OK ){
aData[18] = (u8)iVersion;
aData[19] = (u8)iVersion;
}
}
}
}
pBt->doNotUseWAL = 0;
return rc;
}
+3
View File
@@ -81,6 +81,7 @@ int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
int sqlite3BtreeMaxPageCount(Btree*,int);
u32 sqlite3BtreeLastPage(Btree*);
int sqlite3BtreeSecureDelete(Btree*,int);
int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
@@ -185,6 +186,8 @@ int sqlite3BtreePutData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeCacheOverflow(BtCursor *);
void sqlite3BtreeClearCursor(BtCursor *);
int sqlite3BtreeSetVersion(Btree *pBt, int iVersion);
#ifndef NDEBUG
int sqlite3BtreeCursorIsValid(BtCursor*);
#endif
+3
View File
@@ -408,6 +408,7 @@ struct BtShared {
u8 readOnly; /* True if the underlying file is readonly */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
u8 secureDelete; /* True if secure_delete is enabled */
u8 initiallyEmpty; /* Database is empty at start of transaction */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
@@ -419,7 +420,9 @@ struct BtShared {
u16 maxLeaf; /* Maximum local payload in a LEAFDATA table */
u16 minLeaf; /* Minimum local payload in a LEAFDATA table */
u8 inTransaction; /* Transaction state */
u8 doNotUseWAL; /* If true, do not open write-ahead-log file */
int nTransaction; /* Number of open transactions (read + write) */
u32 nPage; /* Number of pages in the database */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */
+6 -1
View File
@@ -353,14 +353,19 @@ FuncDef *sqlite3FindFunction(
/* If no match is found, search the built-in functions.
**
** If the SQLITE_PreferBuiltin flag is set, then search the built-in
** functions even if a prior app-defined function was found. And give
** priority to built-in functions.
**
** Except, if createFlag is true, that means that we are trying to
** install a new function. Whatever FuncDef structure is returned will
** have fields overwritten with new information appropriate for the
** new function. But the FuncDefs for built-in functions are read-only.
** So we must not search for built-ins when creating a new function.
*/
if( !createFlag && !pBest ){
if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
bestScore = 0;
p = functionSearch(pHash, h, zName, nName);
while( p ){
int score = matchQuality(p, nArg, enc);
+3
View File
@@ -171,6 +171,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_OMIT_AUTOINIT
"OMIT_AUTOINIT",
#endif
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
"OMIT_AUTOMATIC_INDEX",
#endif
#ifdef SQLITE_OMIT_AUTOVACUUM
"OMIT_AUTOVACUUM",
#endif
+4 -13
View File
@@ -314,10 +314,8 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** Set the time to the current time reported by the VFS
*/
static void setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
double r;
sqlite3 *db = sqlite3_context_db_handle(context);
sqlite3OsCurrentTime(db->pVfs, &r);
p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
sqlite3OsCurrentTimeInt64(db->pVfs, &p->iJD);
p->validJD = 1;
}
@@ -1038,22 +1036,15 @@ static void currentTimeFunc(
time_t t;
char *zFormat = (char *)sqlite3_user_data(context);
sqlite3 *db;
double rT;
sqlite3_int64 iT;
char zBuf[20];
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
db = sqlite3_context_db_handle(context);
sqlite3OsCurrentTime(db->pVfs, &rT);
#ifndef SQLITE_OMIT_FLOATING_POINT
t = 86400.0*(rT - 2440587.5) + 0.5;
#else
/* without floating point support, rT will have
** already lost fractional day precision.
*/
t = 86400 * (rT - 2440587) - 43200;
#endif
sqlite3OsCurrentTimeInt64(db->pVfs, &iT);
t = iT/1000 - 10000*(sqlite3_int64)21086676;
#ifdef HAVE_GMTIME_R
{
struct tm sNow;
+29 -31
View File
@@ -2353,27 +2353,12 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
#endif
case TK_VARIABLE: {
VdbeOp *pOp;
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( pExpr->u.zToken!=0 );
assert( pExpr->u.zToken[0]!=0 );
if( pExpr->u.zToken[1]==0
&& (pOp = sqlite3VdbeGetOp(v, -1))->opcode==OP_Variable
&& pOp->p1+pOp->p3==pExpr->iColumn
&& pOp->p2+pOp->p3==target
&& pOp->p4.z==0
){
/* If the previous instruction was a copy of the previous unnamed
** parameter into the previous register, then simply increment the
** repeat count on the prior instruction rather than making a new
** instruction.
*/
pOp->p3++;
}else{
sqlite3VdbeAddOp3(v, OP_Variable, pExpr->iColumn, target, 1);
if( pExpr->u.zToken[1]!=0 ){
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
}
sqlite3VdbeAddOp2(v, OP_Variable, pExpr->iColumn, target);
if( pExpr->u.zToken[1]!=0 ){
sqlite3VdbeChangeP4(v, -1, pExpr->u.zToken, 0);
}
break;
}
@@ -3440,7 +3425,6 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
** an incorrect 0 or 1 could lead to a malfunction.
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB){
int i;
if( pA==0||pB==0 ){
return pB==pA ? 0 : 2;
}
@@ -3453,18 +3437,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
if( pA->op!=pB->op ) return 2;
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
if( pA->x.pList && pB->x.pList ){
if( pA->x.pList->nExpr!=pB->x.pList->nExpr ) return 2;
for(i=0; i<pA->x.pList->nExpr; i++){
Expr *pExprA = pA->x.pList->a[i].pExpr;
Expr *pExprB = pB->x.pList->a[i].pExpr;
if( sqlite3ExprCompare(pExprA, pExprB) ) return 2;
}
}else if( pA->x.pList || pB->x.pList ){
return 2;
}
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
if( ExprHasProperty(pA, EP_IntValue) ){
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
@@ -3481,6 +3454,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
return 0;
}
/*
** Compare two ExprList objects. Return 0 if they are identical and
** non-zero if they differ in any way.
**
** This routine might return non-zero for equivalent ExprLists. The
** only consequence will be disabled optimizations. But this routine
** must never return 0 if the two ExprList objects are different, or
** a malfunction will result.
**
** Two NULL pointers are considered to be the same. But a NULL pointer
** always differs from a non-NULL pointer.
*/
int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
int i;
if( pA==0 && pB==0 ) return 0;
if( pA==0 || pB==0 ) return 1;
if( pA->nExpr!=pB->nExpr ) return 1;
for(i=0; i<pA->nExpr; i++){
Expr *pExprA = pA->a[i].pExpr;
Expr *pExprB = pB->a[i].pExpr;
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
}
return 0;
}
/*
** Add a new element to the pAggInfo->aCol[] array. Return the index of
+10 -12
View File
@@ -1411,20 +1411,15 @@ static void groupConcatFinalize(sqlite3_context *context){
}
/*
** This function registered all of the above C functions as SQL
** functions. This should be the only routine in this file with
** external linkage.
** This routine does per-connection function registration. Most
** of the built-in functions above are part of the global function set.
** This routine only deals with those that are not global.
*/
void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions(db);
#endif
if( !db->mallocFailed ){
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
int rc = sqlite3_overload_function(db, "MATCH", 2);
assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}
}
@@ -1592,4 +1587,7 @@ void sqlite3RegisterGlobalFunctions(void){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
sqlite3RegisterDateTimeFunctions();
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
}
+1 -1
View File
@@ -846,7 +846,7 @@ void sqlite3Insert(
if( pColumn->a[j].idx==i ) break;
}
}
if( pColumn && j>=pColumn->nId ){
if( (!useTempTable && !pList) || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i+1);
}else if( useTempTable ){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i+1);
+140 -1
View File
@@ -1186,6 +1186,143 @@ void *sqlite3_rollback_hook(
return pRet;
}
#ifndef SQLITE_OMIT_WAL
/*
** The sqlite3_wal_hook() callback registered by sqlite3_wal_autocheckpoint().
** Invoke sqlite3_wal_checkpoint if the number of frames in the log file
** is greater than sqlite3.pWalArg cast to an integer (the value configured by
** wal_autocheckpoint()).
*/
int sqlite3WalDefaultHook(
void *pClientData, /* Argument */
sqlite3 *db, /* Connection */
const char *zDb, /* Database */
int nFrame /* Size of WAL */
){
if( nFrame>=SQLITE_PTR_TO_INT(pClientData) ){
sqlite3_wal_checkpoint(db, zDb);
}
return SQLITE_OK;
}
#endif /* SQLITE_OMIT_WAL */
/*
** Configure an sqlite3_wal_hook() callback to automatically checkpoint
** a database after committing a transaction if there are nFrame or
** more frames in the log file. Passing zero or a negative value as the
** nFrame parameter disables automatic checkpoints entirely.
**
** The callback registered by this function replaces any existing callback
** registered using sqlite3_wal_hook(). Likewise, registering a callback
** using sqlite3_wal_hook() disables the automatic checkpoint mechanism
** configured by this function.
*/
int sqlite3_wal_autocheckpoint(sqlite3 *db, int nFrame){
#ifndef SQLITE_OMIT_WAL
if( nFrame>0 ){
sqlite3_wal_hook(db, sqlite3WalDefaultHook, SQLITE_INT_TO_PTR(nFrame));
}else{
sqlite3_wal_hook(db, 0, 0);
}
#endif
return SQLITE_OK;
}
/*
** Register a callback to be invoked each time a transaction is written
** into the write-ahead-log by this database connection.
*/
void *sqlite3_wal_hook(
sqlite3 *db, /* Attach the hook to this db handle */
int(*xCallback)(void *, sqlite3*, const char*, int),
void *pArg /* First argument passed to xCallback() */
){
#ifndef SQLITE_OMIT_WAL
void *pRet;
sqlite3_mutex_enter(db->mutex);
pRet = db->pWalArg;
db->xWalCallback = xCallback;
db->pWalArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pRet;
#else
return 0;
#endif
}
/*
** Checkpoint database zDb. If zDb is NULL, or if the buffer zDb points
** to contains a zero-length string, all attached databases are
** checkpointed.
*/
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
#ifdef SQLITE_OMIT_WAL
return SQLITE_OK;
#else
int rc; /* Return code */
int iDb = SQLITE_MAX_ATTACHED; /* sqlite3.aDb[] index of db to checkpoint */
sqlite3_mutex_enter(db->mutex);
if( zDb && zDb[0] ){
iDb = sqlite3FindDbName(db, zDb);
}
if( iDb<0 ){
rc = SQLITE_ERROR;
sqlite3Error(db, SQLITE_ERROR, "unknown database: %s", zDb);
}else{
rc = sqlite3Checkpoint(db, iDb);
sqlite3Error(db, rc, 0);
}
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
return rc;
#endif
}
#ifndef SQLITE_OMIT_WAL
/*
** Run a checkpoint on database iDb. This is a no-op if database iDb is
** not currently open in WAL mode.
**
** If a transaction is open on the database being checkpointed, this
** function returns SQLITE_LOCKED and a checkpoint is not attempted. If
** an error occurs while running the checkpoint, an SQLite error code is
** returned (i.e. SQLITE_IOERR). Otherwise, SQLITE_OK.
**
** The mutex on database handle db should be held by the caller. The mutex
** associated with the specific b-tree being checkpointed is taken by
** this function while the checkpoint is running.
**
** If iDb is passed SQLITE_MAX_ATTACHED, then all attached databases are
** checkpointed. If an error is encountered it is returned immediately -
** no attempt is made to checkpoint any remaining databases.
*/
int sqlite3Checkpoint(sqlite3 *db, int iDb){
int rc = SQLITE_OK; /* Return code */
int i; /* Used to iterate through attached dbs */
assert( sqlite3_mutex_held(db->mutex) );
for(i=0; i<db->nDb && rc==SQLITE_OK; i++){
if( i==iDb || iDb==SQLITE_MAX_ATTACHED ){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
if( sqlite3BtreeIsInReadTrans(pBt) ){
rc = SQLITE_LOCKED;
}else{
sqlite3BtreeEnter(pBt);
rc = sqlite3PagerCheckpoint(sqlite3BtreePager(pBt));
sqlite3BtreeLeave(pBt);
}
}
}
}
return rc;
}
#endif /* SQLITE_OMIT_WAL */
/*
** This function returns true if main-memory should be used instead of
** a temporary file for transient pager files and statement journals.
@@ -1608,7 +1745,7 @@ static int openDatabase(
db->autoCommit = 1;
db->nextAutovac = -1;
db->nextPagesize = 0;
db->flags |= SQLITE_ShortColNames
db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
@@ -1746,6 +1883,8 @@ static int openDatabase(
setupLookaside(db, 0, sqlite3GlobalConfig.szLookaside,
sqlite3GlobalConfig.nLookaside);
sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT);
opendb_out:
if( db ){
assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 );
+16
View File
@@ -356,6 +356,7 @@ scratch_overflow:
}else{
p = sqlite3GlobalConfig.m.xMalloc(n);
}
sqlite3MemdebugSetType(p, MEMTYPE_SCRATCH);
#if SQLITE_THREADSAFE==0 && !defined(NDEBUG)
scratchAllocOut = p!=0;
#endif
@@ -376,6 +377,8 @@ void sqlite3ScratchFree(void *p){
if( sqlite3GlobalConfig.pScratch==0
|| p<sqlite3GlobalConfig.pScratch
|| p>=(void*)mem0.aScratchFree ){
assert( sqlite3MemdebugHasType(p, MEMTYPE_SCRATCH) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
if( sqlite3GlobalConfig.bMemstat ){
int iSize = sqlite3MallocSize(p);
sqlite3_mutex_enter(mem0.mutex);
@@ -416,6 +419,7 @@ static int isLookaside(sqlite3 *db, void *p){
** sqlite3Malloc() or sqlite3_malloc().
*/
int sqlite3MallocSize(void *p){
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
int sqlite3DbMallocSize(sqlite3 *db, void *p){
@@ -423,6 +427,8 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
if( isLookaside(db, p) ){
return db->lookaside.sz;
}else{
assert( sqlite3MemdebugHasType(p,
db ? (MEMTYPE_DB|MEMTYPE_HEAP) : MEMTYPE_HEAP) );
return sqlite3GlobalConfig.m.xSize(p);
}
}
@@ -432,6 +438,7 @@ int sqlite3DbMallocSize(sqlite3 *db, void *p){
*/
void sqlite3_free(void *p){
if( p==0 ) return;
assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
if( sqlite3GlobalConfig.bMemstat ){
sqlite3_mutex_enter(mem0.mutex);
sqlite3StatusAdd(SQLITE_STATUS_MEMORY_USED, -sqlite3MallocSize(p));
@@ -454,6 +461,8 @@ void sqlite3DbFree(sqlite3 *db, void *p){
db->lookaside.pFree = pBuf;
db->lookaside.nOut--;
}else{
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
sqlite3_free(p);
}
}
@@ -486,6 +495,7 @@ void *sqlite3Realloc(void *pOld, int nBytes){
mem0.alarmThreshold ){
sqlite3MallocAlarm(nNew-nOld);
}
assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) );
pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew);
if( pNew==0 && mem0.alarmCallback ){
sqlite3MallocAlarm(nBytes);
@@ -583,6 +593,8 @@ void *sqlite3DbMallocRaw(sqlite3 *db, int n){
if( !p && db ){
db->mallocFailed = 1;
}
sqlite3MemdebugSetType(p,
(db && db->lookaside.bEnabled) ? MEMTYPE_DB : MEMTYPE_HEAP);
return p;
}
@@ -608,10 +620,14 @@ void *sqlite3DbRealloc(sqlite3 *db, void *p, int n){
sqlite3DbFree(db, p);
}
}else{
assert( sqlite3MemdebugHasType(p, MEMTYPE_DB|MEMTYPE_HEAP) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
pNew = sqlite3_realloc(p, n);
if( !pNew ){
db->mallocFailed = 1;
}
sqlite3MemdebugSetType(pNew,
db->lookaside.bEnabled ? MEMTYPE_DB : MEMTYPE_HEAP);
}
}
return pNew;
+44 -1
View File
@@ -57,7 +57,8 @@ struct MemBlockHdr {
struct MemBlockHdr *pNext, *pPrev; /* Linked list of all unfreed memory */
char nBacktrace; /* Number of backtraces on this alloc */
char nBacktraceSlots; /* Available backtrace slots */
short nTitle; /* Bytes of title; includes '\0' */
u8 nTitle; /* Bytes of title; includes '\0' */
u8 eType; /* Allocation type code */
int iForeGuard; /* Guard word for sanity */
};
@@ -265,6 +266,7 @@ static void *sqlite3MemMalloc(int nByte){
}
mem.pLast = pHdr;
pHdr->iForeGuard = FOREGUARD;
pHdr->eType = MEMTYPE_HEAP;
pHdr->nBacktraceSlots = mem.nBacktrace;
pHdr->nTitle = mem.nTitle;
if( mem.nBacktrace ){
@@ -372,6 +374,47 @@ void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, &defaultMethods);
}
/*
** Set the "type" of an allocation.
*/
void sqlite3MemdebugSetType(void *p, u8 eType){
if( p ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD );
pHdr->eType = eType;
}
}
/*
** Return TRUE if the mask of type in eType matches the type of the
** allocation p. Also return true if p==NULL.
**
** This routine is designed for use within an assert() statement, to
** verify the type of an allocation. For example:
**
** assert( sqlite3MemdebugHasType(p, MEMTYPE_DB) );
*/
int sqlite3MemdebugHasType(void *p, u8 eType){
int rc = 1;
if( p ){
struct MemBlockHdr *pHdr;
pHdr = sqlite3MemsysGetHeader(p);
assert( pHdr->iForeGuard==FOREGUARD ); /* Allocation is valid */
assert( (pHdr->eType & (pHdr->eType-1))==0 ); /* Only one type bit set */
if( (pHdr->eType&eType)==0 ){
void **pBt;
pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
backtrace_symbols_fd(pBt, pHdr->nBacktrace, fileno(stderr));
fprintf(stderr, "\n");
rc = 0;
}
}
return rc;
}
/*
** Set the number of backtrace levels kept for each allocation.
** A value of zero turns off backtracing. The number is always rounded
+4 -5
View File
@@ -196,11 +196,10 @@ static int memjrnlClose(sqlite3_file *pJfd){
** exists purely as a contingency, in case some malfunction in some other
** part of SQLite causes Sync to be called by mistake.
*/
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
assert( 0 ); /*NO_TEST*/
return SQLITE_OK; /*NO_TEST*/
} /*NO_TEST*/
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){
UNUSED_PARAMETER2(NotUsed, NotUsed2);
return SQLITE_OK;
}
/*
** Query the size of the file in bytes.
+17 -14
View File
@@ -31,23 +31,26 @@ static SQLITE_WSD int mutexIsInit = 0;
*/
int sqlite3MutexInit(void){
int rc = SQLITE_OK;
if( sqlite3GlobalConfig.bCoreMutex ){
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
/* If the xMutexAlloc method has not been set, then the user did not
** install a mutex implementation via sqlite3_config() prior to
** sqlite3_initialize() being called. This block copies pointers to
** the default implementation into the sqlite3GlobalConfig structure.
*/
sqlite3_mutex_methods *pFrom = sqlite3DefaultMutex();
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
if( !sqlite3GlobalConfig.mutex.xMutexAlloc ){
/* If the xMutexAlloc method has not been set, then the user did not
** install a mutex implementation via sqlite3_config() prior to
** sqlite3_initialize() being called. This block copies pointers to
** the default implementation into the sqlite3GlobalConfig structure.
*/
sqlite3_mutex_methods *pFrom;
sqlite3_mutex_methods *pTo = &sqlite3GlobalConfig.mutex;
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
pTo->xMutexAlloc = pFrom->xMutexAlloc;
if( sqlite3GlobalConfig.bCoreMutex ){
pFrom = sqlite3DefaultMutex();
}else{
pFrom = sqlite3NoopMutex();
}
rc = sqlite3GlobalConfig.mutex.xMutexInit();
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));
memcpy(&pTo->xMutexFree, &pFrom->xMutexFree,
sizeof(*pTo) - offsetof(sqlite3_mutex_methods, xMutexFree));
pTo->xMutexAlloc = pFrom->xMutexAlloc;
}
rc = sqlite3GlobalConfig.mutex.xMutexInit();
#ifdef SQLITE_DEBUG
GLOBAL(int, mutexIsInit) = 1;
+41 -25
View File
@@ -27,15 +27,14 @@
*/
#include "sqliteInt.h"
#ifndef SQLITE_MUTEX_OMIT
#if defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG)
#ifndef SQLITE_DEBUG
/*
** Stub routines for all mutex methods.
**
** This routines provide no mutual exclusion or error checking.
*/
static int noopMutexHeld(sqlite3_mutex *p){ return 1; }
static int noopMutexNotheld(sqlite3_mutex *p){ return 1; }
static int noopMutexInit(void){ return SQLITE_OK; }
static int noopMutexEnd(void){ return SQLITE_OK; }
static sqlite3_mutex *noopMutexAlloc(int id){ return (sqlite3_mutex*)8; }
@@ -44,7 +43,7 @@ static void noopMutexEnter(sqlite3_mutex *p){ return; }
static int noopMutexTry(sqlite3_mutex *p){ return SQLITE_OK; }
static void noopMutexLeave(sqlite3_mutex *p){ return; }
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
sqlite3_mutex_methods *sqlite3NoopMutex(void){
static sqlite3_mutex_methods sMutex = {
noopMutexInit,
noopMutexEnd,
@@ -54,15 +53,15 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
noopMutexTry,
noopMutexLeave,
noopMutexHeld,
noopMutexNotheld
0,
0,
};
return &sMutex;
}
#endif /* defined(SQLITE_MUTEX_NOOP) && !defined(SQLITE_DEBUG) */
#endif /* !SQLITE_DEBUG */
#if defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG)
#ifdef SQLITE_DEBUG
/*
** In this implementation, error checking is provided for testing
** and debugging purposes. The mutexes still do not provide any
@@ -72,19 +71,21 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
/*
** The mutex object
*/
struct sqlite3_mutex {
typedef struct sqlite3_debug_mutex {
int id; /* The mutex type */
int cnt; /* Number of entries without a matching leave */
};
} sqlite3_debug_mutex;
/*
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
** intended for use inside assert() statements.
*/
static int debugMutexHeld(sqlite3_mutex *p){
static int debugMutexHeld(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt>0;
}
static int debugMutexNotheld(sqlite3_mutex *p){
static int debugMutexNotheld(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
return p==0 || p->cnt==0;
}
@@ -100,8 +101,8 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
static sqlite3_mutex aStatic[6];
sqlite3_mutex *pNew = 0;
static sqlite3_debug_mutex aStatic[6];
sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
case SQLITE_MUTEX_RECURSIVE: {
@@ -120,13 +121,14 @@ static sqlite3_mutex *debugMutexAlloc(int id){
break;
}
}
return pNew;
return (sqlite3_mutex*)pNew;
}
/*
** This routine deallocates a previously allocated mutex.
*/
static void debugMutexFree(sqlite3_mutex *p){
static void debugMutexFree(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->cnt==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
sqlite3_free(p);
@@ -143,12 +145,14 @@ static void debugMutexFree(sqlite3_mutex *p){
** can enter. If the same thread tries to enter any other kind of mutex
** more than once, the behavior is undefined.
*/
static void debugMutexEnter(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
static void debugMutexEnter(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
}
static int debugMutexTry(sqlite3_mutex *p){
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
static int debugMutexTry(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
p->cnt++;
return SQLITE_OK;
}
@@ -159,13 +163,14 @@ static int debugMutexTry(sqlite3_mutex *p){
** is undefined if the mutex is not currently entered or
** is not currently allocated. SQLite will never do either.
*/
static void debugMutexLeave(sqlite3_mutex *p){
assert( debugMutexHeld(p) );
static void debugMutexLeave(sqlite3_mutex *pX){
sqlite3_debug_mutex *p = (sqlite3_debug_mutex*)pX;
assert( debugMutexHeld(pX) );
p->cnt--;
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(p) );
assert( p->id==SQLITE_MUTEX_RECURSIVE || debugMutexNotheld(pX) );
}
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
sqlite3_mutex_methods *sqlite3NoopMutex(void){
static sqlite3_mutex_methods sMutex = {
debugMutexInit,
debugMutexEnd,
@@ -181,4 +186,15 @@ sqlite3_mutex_methods *sqlite3DefaultMutex(void){
return &sMutex;
}
#endif /* defined(SQLITE_MUTEX_NOOP) && defined(SQLITE_DEBUG) */
#endif /* SQLITE_DEBUG */
/*
** If compiled with SQLITE_MUTEX_NOOP, then the no-op mutex implementation
** is used regardless of the run-time threadsafety setting.
*/
#ifdef SQLITE_MUTEX_NOOP
sqlite3_mutex_methods *sqlite3DefaultMutex(void){
return sqliteNoopMutex();
}
#endif /* SQLITE_MUTEX_NOOP */
#endif /* SQLITE_MUTEX_OMIT */
+1
View File
@@ -157,6 +157,7 @@ int sqlite3_unlock_notify(
if( xNotify==0 ){
removeFromBlockedList(db);
db->pBlockingConnection = 0;
db->pUnlockConnection = 0;
db->xUnlockNotify = 0;
db->pUnlockArg = 0;
+28 -2
View File
@@ -98,6 +98,24 @@ int sqlite3OsSectorSize(sqlite3_file *id){
int sqlite3OsDeviceCharacteristics(sqlite3_file *id){
return id->pMethods->xDeviceCharacteristics(id);
}
int sqlite3OsShmOpen(sqlite3_file *id){
return id->pMethods->xShmOpen(id);
}
int sqlite3OsShmSize(sqlite3_file *id, int reqSize, int *pNewSize){
return id->pMethods->xShmSize(id, reqSize, pNewSize);
}
int sqlite3OsShmGet(sqlite3_file *id, int reqSize, int *pSize, void **pp){
return id->pMethods->xShmGet(id, reqSize, pSize, pp);
}
int sqlite3OsShmRelease(sqlite3_file *id){
return id->pMethods->xShmRelease(id);
}
int sqlite3OsShmLock(sqlite3_file *id, int desiredLock, int *pGotLock){
return id->pMethods->xShmLock(id, desiredLock, pGotLock);
}
int sqlite3OsShmClose(sqlite3_file *id, int deleteFlag){
return id->pMethods->xShmClose(id, deleteFlag);
}
/*
** The next group of routines are convenience wrappers around the
@@ -161,8 +179,16 @@ int sqlite3OsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
int sqlite3OsSleep(sqlite3_vfs *pVfs, int nMicro){
return pVfs->xSleep(pVfs, nMicro);
}
int sqlite3OsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return pVfs->xCurrentTime(pVfs, pTimeOut);
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
int rc;
if( pVfs->iVersion>=2 && pVfs->xCurrentTimeInt64 ){
rc = pVfs->xCurrentTimeInt64(pVfs, pTimeOut);
}else{
double r;
rc = pVfs->xCurrentTime(pVfs, &r);
*pTimeOut = (sqlite3_int64)(r*86400000.0);
}
return rc;
}
int sqlite3OsOpenMalloc(
+7 -1
View File
@@ -243,6 +243,12 @@ int sqlite3OsFileControl(sqlite3_file*,int,void*);
#define SQLITE_FCNTL_DB_UNCHANGED 0xca093fa0
int sqlite3OsSectorSize(sqlite3_file *id);
int sqlite3OsDeviceCharacteristics(sqlite3_file *id);
int sqlite3OsShmOpen(sqlite3_file *id);
int sqlite3OsShmSize(sqlite3_file *id, int, int*);
int sqlite3OsShmGet(sqlite3_file *id, int, int*, void**);
int sqlite3OsShmRelease(sqlite3_file *id);
int sqlite3OsShmLock(sqlite3_file *id, int, int*);
int sqlite3OsShmClose(sqlite3_file *id, int);
/*
** Functions for accessing sqlite3_vfs methods
@@ -259,7 +265,7 @@ void sqlite3OsDlClose(sqlite3_vfs *, void *);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
int sqlite3OsRandomness(sqlite3_vfs *, int, char *);
int sqlite3OsSleep(sqlite3_vfs *, int);
int sqlite3OsCurrentTime(sqlite3_vfs *, double*);
int sqlite3OsCurrentTimeInt64(sqlite3_vfs *, sqlite3_int64*);
/*
** Convenience functions for opening and closing files using
+2
View File
@@ -40,6 +40,7 @@ int sqlite3OSTrace = 0;
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
#define OSTRACE7(X,Y,Z,A,B,C,D) \
if(sqlite3OSTrace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
#define OSTRACE(X) if( sqlite3OSTrace ) sqlite3DebugPrintf X
#else
#define OSTRACE1(X)
#define OSTRACE2(X,Y)
@@ -48,6 +49,7 @@ int sqlite3OSTrace = 0;
#define OSTRACE5(X,Y,Z,A,B)
#define OSTRACE6(X,Y,Z,A,B,C)
#define OSTRACE7(X,Y,Z,A,B,C,D)
#define OSTRACE(X)
#endif
/*
+1 -1
View File
@@ -1111,7 +1111,7 @@ int sqlite3_os_init(void){
os2Randomness, /* xRandomness */
os2Sleep, /* xSleep */
os2CurrentTime, /* xCurrentTime */
os2GetLastError /* xGetLastError */
os2GetLastError, /* xGetLastError */
};
sqlite3_vfs_register(&os2Vfs, 1);
initUconvObjects();
+885 -30
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1912,7 +1912,7 @@ int sqlite3_os_init(void){
winRandomness, /* xRandomness */
winSleep, /* xSleep */
winCurrentTime, /* xCurrentTime */
winGetLastError /* xGetLastError */
winGetLastError, /* xGetLastError */
};
sqlite3_vfs_register(&winVfs, 1);
+989 -362
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -76,6 +76,7 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_OFF 2 /* Journal omitted. */
#define PAGER_JOURNALMODE_TRUNCATE 3 /* Commit by truncating journal */
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** The remainder of this file contains the declarations of the functions
@@ -133,9 +134,16 @@ int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
int sqlite3PagerSharedLock(Pager *pPager);
int sqlite3PagerCheckpoint(Pager *pPager);
int sqlite3PagerWalSupported(Pager *pPager);
int sqlite3PagerWalCallback(Pager *pPager);
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
int sqlite3PagerCloseWal(Pager *pPager);
/* Functions used to query pager state and configuration. */
u8 sqlite3PagerIsreadonly(Pager*);
int sqlite3PagerRefcount(Pager*);
int sqlite3PagerMemUsed(Pager*);
const char *sqlite3PagerFilename(Pager*);
const sqlite3_vfs *sqlite3PagerVfs(Pager*);
sqlite3_file *sqlite3PagerFile(Pager*);
+6 -1
View File
@@ -407,7 +407,12 @@ void sqlite3PcacheTruncate(PCache *pCache, Pgno pgno){
PgHdr *pNext;
for(p=pCache->pDirty; p; p=pNext){
pNext = p->pDirtyNext;
if( p->pgno>pgno ){
/* This routine never gets call with a positive pgno except right
** after sqlite3PcacheCleanAll(). So if there are dirty pages,
** it must be that pgno==0.
*/
assert( p->pgno>0 );
if( ALWAYS(p->pgno>pgno) ){
assert( p->flags&PGHDR_DIRTY );
sqlite3PcacheMakeClean(p);
}
+5 -1
View File
@@ -173,6 +173,7 @@ static void *pcache1Alloc(int nByte){
int sz = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, sz);
}
sqlite3MemdebugSetType(p, MEMTYPE_PCACHE);
}
return p;
}
@@ -190,7 +191,10 @@ static void pcache1Free(void *p){
pSlot->pNext = pcache1.pFree;
pcache1.pFree = pSlot;
}else{
int iSize = sqlite3MallocSize(p);
int iSize;
assert( sqlite3MemdebugHasType(p, MEMTYPE_PCACHE) );
sqlite3MemdebugSetType(p, MEMTYPE_HEAP);
iSize = sqlite3MallocSize(p);
sqlite3StatusAdd(SQLITE_STATUS_PAGECACHE_OVERFLOW, -iSize);
sqlite3_free(p);
}
+90 -40
View File
@@ -173,6 +173,9 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
{ "automatic_index", SQLITE_AutoIndex },
#endif
#ifdef SQLITE_DEBUG
{ "sql_trace", SQLITE_SqlTrace },
{ "vdbe_listing", SQLITE_VdbeListing },
@@ -254,6 +257,31 @@ static const char *actionName(u8 action){
}
#endif
/*
** Parameter eMode must be one of the PAGER_JOURNALMODE_XXX constants
** defined in pager.h. This function returns the associated lowercase
** journal-mode name.
*/
const char *sqlite3JournalModename(int eMode){
static char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory"
#ifndef SQLITE_OMIT_WAL
, "wal"
#endif
};
assert( PAGER_JOURNALMODE_DELETE==0 );
assert( PAGER_JOURNALMODE_PERSIST==1 );
assert( PAGER_JOURNALMODE_OFF==2 );
assert( PAGER_JOURNALMODE_TRUNCATE==3 );
assert( PAGER_JOURNALMODE_MEMORY==4 );
assert( PAGER_JOURNALMODE_WAL==5 );
assert( eMode>=0 && eMode<=ArraySize(azModeName) );
if( eMode==ArraySize(azModeName) ) return 0;
return azModeName[eMode];
}
/*
** Process a pragma statement.
**
@@ -326,11 +354,11 @@ void sqlite3Pragma(
** page cache size value and the persistent page cache size value
** stored in the database file.
**
** The default cache size is stored in meta-value 2 of page 1 of the
** database file. The cache size is actually the absolute value of
** this memory location. The sign of meta-value 2 determines the
** synchronous setting. A negative value means synchronous is off
** and a positive value means synchronous is on.
** Older versions of SQLite would set the default cache size to a
** negative number to indicate synchronous=OFF. These days, synchronous
** is always on by default regardless of the sign of the default cache
** size. But continue to take the absolute value of the default cache
** size of historical compatibility.
*/
if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){
static const VdbeOpList getCacheSize[] = {
@@ -359,10 +387,6 @@ void sqlite3Pragma(
if( size<0 ) size = -size;
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, 2, BTREE_DEFAULT_CACHE_SIZE);
addr = sqlite3VdbeAddOp2(v, OP_IfPos, 2, 0);
sqlite3VdbeAddOp2(v, OP_Integer, -size, 1);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
pDb->pSchema->cache_size = size;
sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
@@ -507,21 +531,25 @@ void sqlite3Pragma(
/*
** PRAGMA [database.]journal_mode
** PRAGMA [database.]journal_mode = (delete|persist|off|truncate|memory)
** PRAGMA [database.]journal_mode =
** (delete|persist|off|truncate|memory|wal|off)
*/
if( sqlite3StrICmp(zLeft,"journal_mode")==0 ){
int eMode;
static char * const azModeName[] = {
"delete", "persist", "off", "truncate", "memory"
};
int eMode; /* One of the PAGER_JOURNALMODE_XXX symbols */
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
if( zRight==0 ){
eMode = PAGER_JOURNALMODE_QUERY;
}else{
const char *zMode;
int n = sqlite3Strlen30(zRight);
eMode = sizeof(azModeName)/sizeof(azModeName[0]) - 1;
while( eMode>=0 && sqlite3StrNICmp(zRight, azModeName[eMode], n)!=0 ){
eMode--;
for(eMode=0; (zMode = sqlite3JournalModename(eMode)); eMode++){
if( sqlite3StrNICmp(zRight, zMode, n)==0 ) break;
}
if( !zMode ){
eMode = PAGER_JOURNALMODE_QUERY;
}
}
if( pId2->n==0 && eMode==PAGER_JOURNALMODE_QUERY ){
@@ -530,39 +558,31 @@ void sqlite3Pragma(
** the journal-mode of the main database).
*/
eMode = db->dfltJournalMode;
sqlite3VdbeAddOp2(v, OP_String8, 0, 1);
sqlite3VdbeChangeP4(v, -1, sqlite3JournalModename(eMode), P4_STATIC);
}else{
Pager *pPager;
int ii;
if( pId2->n==0 ){
/* This indicates that no database name was specified as part
** of the PRAGMA command. In this case the journal-mode must be
** set on all attached databases, as well as the main db file.
/* When there is no database name before the "journal_mode" keyword
** in the PRAGMA, then the journal-mode will be set on
** all attached databases, as well as the main db file.
**
** Also, the sqlite3.dfltJournalMode variable is set so that
** any subsequently attached databases also use the specified
** journal mode.
*/
int ii;
assert(pDb==&db->aDb[0]);
for(ii=1; ii<db->nDb; ii++){
if( db->aDb[ii].pBt ){
pPager = sqlite3BtreePager(db->aDb[ii].pBt);
sqlite3PagerJournalMode(pPager, eMode);
}
}
db->dfltJournalMode = (u8)eMode;
}
pPager = sqlite3BtreePager(pDb->pBt);
eMode = sqlite3PagerJournalMode(pPager, eMode);
for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3VdbeUsesBtree(v, ii);
sqlite3VdbeAddOp3(v, OP_JournalMode, ii, 1, eMode);
}
}
}
assert( eMode==PAGER_JOURNALMODE_DELETE
|| eMode==PAGER_JOURNALMODE_TRUNCATE
|| eMode==PAGER_JOURNALMODE_PERSIST
|| eMode==PAGER_JOURNALMODE_OFF
|| eMode==PAGER_JOURNALMODE_MEMORY );
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "journal_mode", SQLITE_STATIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0,
azModeName[eMode], P4_STATIC);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
}else
@@ -1380,6 +1400,36 @@ void sqlite3Pragma(
}else
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
#ifndef SQLITE_OMIT_WAL
/*
** PRAGMA [database.]wal_checkpoint
**
** Checkpoint the database.
*/
if( sqlite3StrICmp(zLeft, "wal_checkpoint")==0 ){
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeAddOp3(v, OP_Checkpoint, pId2->z?iDb:SQLITE_MAX_ATTACHED, 0, 0);
}else
/*
** PRAGMA wal_autocheckpoint
** PRAGMA wal_autocheckpoint = N
**
** Configure a database connection to automatically checkpoint a database
** after accumulating N frames in the log. Or query for the current value
** of N.
*/
if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
if( zRight ){
int nAuto = atoi(zRight);
sqlite3_wal_autocheckpoint(db, nAuto);
}
returnSingleInt(pParse, "wal_autocheckpoint",
db->xWalCallback==sqlite3WalDefaultHook ?
SQLITE_PTR_TO_INT(db->pWalArg) : 0);
}else
#endif
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Report the current state of file logs for all databases
+7 -5
View File
@@ -73,15 +73,15 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
** or executed. All the parser does is build the internal data
** structures that describe the table, index, or view.
*/
char *zErr;
int rc;
sqlite3_stmt *pStmt;
assert( db->init.busy );
db->init.iDb = iDb;
db->init.newTnum = atoi(argv[1]);
db->init.orphanTrigger = 0;
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
rc = sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
db->init.iDb = 0;
assert( rc!=SQLITE_OK || zErr==0 );
if( SQLITE_OK!=rc ){
if( db->init.orphanTrigger ){
assert( iDb==1 );
@@ -90,11 +90,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
if( rc==SQLITE_NOMEM ){
db->mallocFailed = 1;
}else if( rc!=SQLITE_INTERRUPT && rc!=SQLITE_LOCKED ){
corruptSchema(pData, argv[0], zErr);
corruptSchema(pData, argv[0], sqlite3_errmsg(db));
}
}
sqlite3DbFree(db, zErr);
}
sqlite3_finalize(pStmt);
}else if( argv[0]==0 ){
corruptSchema(pData, 0, 0);
}else{
@@ -579,6 +579,7 @@ static int sqlite3Prepare(
sqlite3VtabUnlockList(db);
pParse->db = db;
pParse->nQueryLoop = (double)1;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
@@ -600,6 +601,7 @@ static int sqlite3Prepare(
}else{
sqlite3RunParser(pParse, zSql, &zErrMsg);
}
assert( 1==(int)pParse->nQueryLoop );
if( db->mallocFailed ){
pParse->rc = SQLITE_NOMEM;
+3 -1
View File
@@ -403,7 +403,7 @@ lookupname_end:
/*
** Allocate and return a pointer to an expression to load the column iCol
** from datasource iSrc datasource in SrcList pSrc.
** from datasource iSrc in SrcList pSrc.
*/
Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0);
@@ -415,6 +415,8 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
p->iColumn = -1;
}else{
p->iColumn = (ynVar)iCol;
testcase( iCol==BMS );
testcase( iCol==BMS-1 );
pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
}
ExprSetProperty(p, EP_Resolved);
+27 -3
View File
@@ -2526,8 +2526,8 @@ static void substSelect(
** (14) The subquery does not use OFFSET
**
** (15) The outer query is not part of a compound select or the
** subquery does not have both an ORDER BY and a LIMIT clause.
** (See ticket #2339)
** subquery does not have a LIMIT clause.
** (See ticket #2339 and ticket [02a8e81d44]).
**
** (16) The outer query is not an aggregate or the subquery does
** not contain ORDER BY. (Ticket #2942) This used to not matter
@@ -2610,7 +2610,7 @@ static int flattenSubquery(
** and (14). */
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
if( pSub->pOffset ) return 0; /* Restriction (14) */
if( p->pRightmost && pSub->pLimit && pSub->pOrderBy ){
if( p->pRightmost && pSub->pLimit ){
return 0; /* Restriction (15) */
}
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
@@ -3498,6 +3498,18 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
sqlite3ExprCacheClear(pParse);
}
}
/* Before populating the accumulator registers, clear the column cache.
** Otherwise, if any of the required column values are already present
** in registers, sqlite3ExprCode() may use OP_SCopy to copy the value
** to pC->iMem. But by the time the value is used, the original register
** may have been used, invalidating the underlying buffer holding the
** text or blob value. See ticket [883034dcb5].
**
** Another solution would be to change the OP_SCopy used to copy cached
** values to an OP_Copy.
*/
sqlite3ExprCacheClear(pParse);
for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){
sqlite3ExprCode(pParse, pC->pExpr, pC->iMem);
}
@@ -3706,6 +3718,18 @@ int sqlite3Select(
isDistinct = 0;
}
/* If there is both a GROUP BY and an ORDER BY clause and they are
** identical, then disable the ORDER BY clause since the GROUP BY
** will cause elements to come out in the correct order. This is
** an optimization - the correct answer should result regardless.
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
** to disable this optimization for testing purposes.
*/
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
&& (db->flags & SQLITE_GroupByOrder)==0 ){
pOrderBy = 0;
}
/* If there is an ORDER BY clause, then this sorting
** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
+4 -4
View File
@@ -2578,7 +2578,6 @@ int main(int argc, char **argv){
*/
if( zFirstCmd[0]=='.' ){
rc = do_meta_command(zFirstCmd, &data);
return rc;
}else{
open_db(&data);
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
@@ -2625,9 +2624,10 @@ int main(int argc, char **argv){
}
}
set_table_name(&data, 0);
if( db ){
if( sqlite3_close(db)!=SQLITE_OK ){
fprintf(stderr,"Error: cannot close database \"%s\"\n", sqlite3_errmsg(db));
if( data.db ){
if( sqlite3_close(data.db)!=SQLITE_OK ){
fprintf(stderr,"Error: cannot close database \"%s\"\n",
sqlite3_errmsg(db));
rc++;
}
}
+184 -57
View File
@@ -141,7 +141,6 @@ const char *sqlite3_libversion(void);
const char *sqlite3_sourceid(void);
int sqlite3_libversion_number(void);
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
/*
** CAPI3REF: Run-Time Library Compilation Options Diagnostics
**
@@ -164,9 +163,10 @@ int sqlite3_libversion_number(void);
** See also: SQL functions [sqlite_compileoption_used()] and
** [sqlite_compileoption_get()] and the [compile_options pragma].
*/
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
int sqlite3_compileoption_used(const char *zOptName);
const char *sqlite3_compileoption_get(int N);
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
#endif
/*
** CAPI3REF: Test To See If The Library Is Threadsafe
@@ -653,6 +653,14 @@ struct sqlite3_io_methods {
int (*xFileControl)(sqlite3_file*, int op, void *pArg);
int (*xSectorSize)(sqlite3_file*);
int (*xDeviceCharacteristics)(sqlite3_file*);
/* Methods above are valid for version 1 */
int (*xShmOpen)(sqlite3_file*);
int (*xShmSize)(sqlite3_file*, int reqSize, int *pNewSize);
int (*xShmGet)(sqlite3_file*, int reqSize, int *pSize, void**);
int (*xShmRelease)(sqlite3_file*);
int (*xShmLock)(sqlite3_file*, int desiredLock, int *gotLock);
int (*xShmClose)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */
/* Additional methods may be added in future releases */
};
@@ -819,7 +827,7 @@ typedef struct sqlite3_mutex sqlite3_mutex;
*/
typedef struct sqlite3_vfs sqlite3_vfs;
struct sqlite3_vfs {
int iVersion; /* Structure version number */
int iVersion; /* Structure version number (currently 2) */
int szOsFile; /* Size of subclassed sqlite3_file */
int mxPathname; /* Maximum file pathname length */
sqlite3_vfs *pNext; /* Next registered VFS */
@@ -838,8 +846,17 @@ struct sqlite3_vfs {
int (*xSleep)(sqlite3_vfs*, int microseconds);
int (*xCurrentTime)(sqlite3_vfs*, double*);
int (*xGetLastError)(sqlite3_vfs*, int, char *);
/* New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens. */
/*
** The methods above are in version 1 of the sqlite_vfs object
** definition. Those that follow are added in version 2 or later
*/
int (*xRename)(sqlite3_vfs*, const char *zOld, const char *zNew, int dirSync);
int (*xCurrentTimeInt64)(sqlite3_vfs*, sqlite3_int64*);
/*
** The methods above are in versions 1 and 2 of the sqlite_vfs object.
** New fields may be appended in figure versions. The iVersion
** value will increment whenever this happens.
*/
};
/*
@@ -859,6 +876,20 @@ struct sqlite3_vfs {
#define SQLITE_ACCESS_READWRITE 1
#define SQLITE_ACCESS_READ 2
/*
** CAPI3REF: Flags for the xShmLock VFS method
**
** These integer constants define the various locking states that
** an sqlite3_shm object can be in.
*/
#define SQLITE_SHM_UNLOCK 0
#define SQLITE_SHM_READ 1
#define SQLITE_SHM_READ_FULL 2
#define SQLITE_SHM_WRITE 3
#define SQLITE_SHM_PENDING 4
#define SQLITE_SHM_CHECKPOINT 5
#define SQLITE_SHM_RECOVER 6
/*
** CAPI3REF: Initialize The SQLite Library
**
@@ -968,11 +999,10 @@ int sqlite3_os_end(void);
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
*/
SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
int sqlite3_config(int, ...);
/*
** CAPI3REF: Configure database connections
** EXPERIMENTAL
**
** The sqlite3_db_config() interface is used to make configuration
** changes to a [database connection]. The interface is similar to
@@ -992,11 +1022,10 @@ SQLITE_EXPERIMENTAL int sqlite3_config(int, ...);
** ^Calls to sqlite3_db_config() return SQLITE_OK if and only if
** the call is considered successful.
*/
SQLITE_EXPERIMENTAL int sqlite3_db_config(sqlite3*, int op, ...);
int sqlite3_db_config(sqlite3*, int op, ...);
/*
** CAPI3REF: Memory Allocation Routines
** EXPERIMENTAL
**
** An instance of this object defines the interface between SQLite
** and low-level memory allocation routines.
@@ -1078,7 +1107,6 @@ struct sqlite3_mem_methods {
/*
** CAPI3REF: Configuration Options
** EXPERIMENTAL
**
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
@@ -1264,6 +1292,24 @@ struct sqlite3_mem_methods {
** [sqlite3_pcache_methods] object. SQLite copies of the current
** page cache implementation into that object.)^ </dd>
**
** <dt>SQLITE_CONFIG_LOG</dt>
** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a
** function with a call signature of void(*)(void*,int,const char*),
** and a pointer to void. ^If the function pointer is not NULL, it is
** invoked by [sqlite3_log()] to process each logging event. ^If the
** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op.
** ^The void pointer that is the second argument to SQLITE_CONFIG_LOG is
** passed through as the first parameter to the application-defined logger
** function whenever that function is invoked. ^The second parameter to
** the logger function is a copy of the first parameter to the corresponding
** [sqlite3_log()] call and is intended to be a [result code] or an
** [extended result code]. ^The third parameter passed to the logger is
** log message after formatting via [sqlite3_snprintf()].
** The SQLite logging interface is not reentrant; the logger function
** supplied by the application must not invoke any SQLite interface.
** In a multi-threaded application, the application-defined logger
** function must be threadsafe. </dd>
**
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1284,8 +1330,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
/*
** CAPI3REF: Configuration Options
** EXPERIMENTAL
** CAPI3REF: Database Connection Configuration Options
**
** These constants are the available integer configuration options that
** can be passed as the second argument to the [sqlite3_db_config()] interface.
@@ -2061,7 +2106,6 @@ int sqlite3_set_authorizer(
/*
** CAPI3REF: Tracing And Profiling Functions
** EXPERIMENTAL
**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
@@ -2079,7 +2123,7 @@ int sqlite3_set_authorizer(
** the original statement text and an estimate of wall-clock time
** of how long that statement took to run.
*/
SQLITE_EXPERIMENTAL void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
@@ -2872,6 +2916,14 @@ const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
** be the case that the same database connection is being used by two or
** more threads at the same moment in time.
**
** For all versions of SQLite up to and including 3.6.23.1, it was required
** after sqlite3_step() returned anything other than [SQLITE_ROW] that
** [sqlite3_reset()] be called before any subsequent invocation of
** sqlite3_step(). Failure to invoke [sqlite3_reset()] in this way would
** result in an [SQLITE_MISUSE] return from sqlite3_step(). But after
** version 3.6.23.1, sqlite3_step() began calling [sqlite3_reset()]
** automatically in this circumstance rather than returning [SQLITE_MISUSE].
**
** <b>Goofy Interface Alert:</b> In the legacy interface, the sqlite3_step()
** API always returns a generic error code, [SQLITE_ERROR], following any
** error other than [SQLITE_BUSY] and [SQLITE_MISUSE]. You must call
@@ -3684,7 +3736,7 @@ int sqlite3_collation_needed16(
void(*)(void*,sqlite3*,int eTextRep,const void*)
);
#if SQLITE_HAS_CODEC
#ifdef SQLITE_HAS_CODEC
/*
** Specify the key for an encrypted database. This routine should be
** called right after sqlite3_open().
@@ -3867,8 +3919,6 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
** an error or constraint causes an implicit rollback to occur.
** ^The rollback callback is not invoked if a transaction is
** automatically rolled back because the database connection is closed.
** ^The rollback callback is not invoked if a transaction is
** rolled back because a commit callback returned non-zero.
**
** See also the [sqlite3_update_hook()] interface.
*/
@@ -4154,8 +4204,6 @@ int sqlite3_auto_extension(void (*xEntryPoint)(void));
void sqlite3_reset_auto_extension(void);
/*
****** EXPERIMENTAL - subject to change without notice **************
**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -4175,7 +4223,6 @@ typedef struct sqlite3_module sqlite3_module;
/*
** CAPI3REF: Virtual Table Object
** KEYWORDS: sqlite3_module {virtual table module}
** EXPERIMENTAL
**
** This structure, sometimes called a a "virtual table module",
** defines the implementation of a [virtual tables].
@@ -4222,7 +4269,6 @@ struct sqlite3_module {
/*
** CAPI3REF: Virtual Table Indexing Information
** KEYWORDS: sqlite3_index_info
** EXPERIMENTAL
**
** The sqlite3_index_info structure and its substructures is used to
** pass information into and receive the reply from the [xBestIndex]
@@ -4304,7 +4350,6 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Register A Virtual Table Implementation
** EXPERIMENTAL
**
** ^These routines are used to register a new [virtual table module] name.
** ^Module names must be registered before
@@ -4326,13 +4371,13 @@ struct sqlite3_index_info {
** interface is equivalent to sqlite3_create_module_v2() with a NULL
** destructor.
*/
SQLITE_EXPERIMENTAL int sqlite3_create_module(
int sqlite3_create_module(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
void *pClientData /* Client data for xCreate/xConnect */
);
SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
int sqlite3_create_module_v2(
sqlite3 *db, /* SQLite connection to register module with */
const char *zName, /* Name of the module */
const sqlite3_module *p, /* Methods for the module */
@@ -4343,7 +4388,6 @@ SQLITE_EXPERIMENTAL int sqlite3_create_module_v2(
/*
** CAPI3REF: Virtual Table Instance Object
** KEYWORDS: sqlite3_vtab
** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass
** of this object to describe a particular instance
@@ -4369,7 +4413,6 @@ struct sqlite3_vtab {
/*
** CAPI3REF: Virtual Table Cursor Object
** KEYWORDS: sqlite3_vtab_cursor {virtual table cursor}
** EXPERIMENTAL
**
** Every [virtual table module] implementation uses a subclass of the
** following structure to describe cursors that point into the
@@ -4391,18 +4434,16 @@ struct sqlite3_vtab_cursor {
/*
** CAPI3REF: Declare The Schema Of A Virtual Table
** EXPERIMENTAL
**
** ^The [xCreate] and [xConnect] methods of a
** [virtual table module] call this interface
** to declare the format (the names and datatypes of the columns) of
** the virtual tables they implement.
*/
SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
/*
** CAPI3REF: Overload A Function For A Virtual Table
** EXPERIMENTAL
**
** ^(Virtual tables can provide alternative implementations of functions
** using the [xFindFunction] method of the [virtual table module].
@@ -4417,7 +4458,7 @@ SQLITE_EXPERIMENTAL int sqlite3_declare_vtab(sqlite3*, const char *zSQL);
** purpose is to be a placeholder function that can be overloaded
** by a [virtual table].
*/
SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
/*
** The interface to the virtual-table mechanism defined above (back up
@@ -4427,8 +4468,6 @@ SQLITE_EXPERIMENTAL int sqlite3_overload_function(sqlite3*, const char *zFuncNam
**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
**
****** EXPERIMENTAL - subject to change without notice **************
*/
/*
@@ -4771,7 +4810,6 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
/*
** CAPI3REF: Mutex Methods Object
** EXPERIMENTAL
**
** An instance of this structure defines the low-level routines
** used to allocate and use mutexes.
@@ -4988,7 +5026,6 @@ int sqlite3_test_control(int op, ...);
/*
** CAPI3REF: SQLite Runtime Status
** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about the preformance of SQLite, and optionally to reset various
@@ -5016,12 +5053,11 @@ int sqlite3_test_control(int op, ...);
**
** See also: [sqlite3_db_status()]
*/
SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag);
/*
** CAPI3REF: Status Parameters
** EXPERIMENTAL
**
** These integer constants designate various run-time status parameters
** that can be returned by [sqlite3_status()].
@@ -5108,14 +5144,15 @@ SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, i
/*
** CAPI3REF: Database Connection Status
** EXPERIMENTAL
**
** ^This interface is used to retrieve runtime status information
** about a single [database connection]. ^The first argument is the
** database connection object to be interrogated. ^The second argument
** is the parameter to interrogate. ^Currently, the only allowed value
** for the second parameter is [SQLITE_DBSTATUS_LOOKASIDE_USED].
** Additional options will likely appear in future releases of SQLite.
** is an integer constant, taken from the set of
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that
** determiness the parameter to interrogate. The set of
** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely
** to grow in future releases of SQLite.
**
** ^The current value of the requested parameter is written into *pCur
** and the highest instantaneous value is written into *pHiwtr. ^If
@@ -5124,11 +5161,10 @@ SQLITE_EXPERIMENTAL int sqlite3_status(int op, int *pCurrent, int *pHighwater, i
**
** See also: [sqlite3_status()] and [sqlite3_stmt_status()].
*/
SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
/*
** CAPI3REF: Status Parameters for database connections
** EXPERIMENTAL
**
** These constants are the available integer "verbs" that can be passed as
** the second argument to the [sqlite3_db_status()] interface.
@@ -5143,14 +5179,21 @@ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiw
** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt>
** <dd>This parameter returns the number of lookaside memory slots currently
** checked out.</dd>)^
**
** <dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>^This parameter returns the approximate number of of bytes of heap
** memory used by all pager caches associated with the database connection.
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
** checked out.</dd>)^
** </dl>
*/
#define SQLITE_DBSTATUS_LOOKASIDE_USED 0
#define SQLITE_DBSTATUS_CACHE_USED 1
#define SQLITE_DBSTATUS_MAX 1 /* Largest defined DBSTATUS */
/*
** CAPI3REF: Prepared Statement Status
** EXPERIMENTAL
**
** ^(Each prepared statement maintains various
** [SQLITE_STMTSTATUS_SORT | counters] that measure the number
@@ -5172,11 +5215,10 @@ SQLITE_EXPERIMENTAL int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiw
**
** See also: [sqlite3_status()] and [sqlite3_db_status()].
*/
SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
/*
** CAPI3REF: Status Parameters for prepared statements
** EXPERIMENTAL
**
** These preprocessor macros define integer codes that name counter
** values associated with the [sqlite3_stmt_status()] interface.
@@ -5194,14 +5236,21 @@ SQLITE_EXPERIMENTAL int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
** A non-zero value in this counter may indicate an opportunity to
** improvement performance through careful use of indices.</dd>
**
** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt>
** <dd>^This is the number of rows inserted into transient indices that
** were created automatically in order to help joins run faster.
** A non-zero value in this counter may indicate an opportunity to
** improvement performance by adding permanent indices that do not
** need to be reinitialized each time the statement is run.</dd>
**
** </dl>
*/
#define SQLITE_STMTSTATUS_FULLSCAN_STEP 1
#define SQLITE_STMTSTATUS_SORT 2
#define SQLITE_STMTSTATUS_AUTOINDEX 3
/*
** CAPI3REF: Custom Page Cache Object
** EXPERIMENTAL
**
** The sqlite3_pcache type is opaque. It is implemented by
** the pluggable module. The SQLite core has no knowledge of
@@ -5216,7 +5265,6 @@ typedef struct sqlite3_pcache sqlite3_pcache;
/*
** CAPI3REF: Application Defined Page Cache.
** KEYWORDS: {page cache}
** EXPERIMENTAL
**
** ^(The [sqlite3_config]([SQLITE_CONFIG_PCACHE], ...) interface can
** register an alternative page cache implementation by passing in an
@@ -5358,7 +5406,6 @@ struct sqlite3_pcache_methods {
/*
** CAPI3REF: Online Backup Object
** EXPERIMENTAL
**
** The sqlite3_backup object records state information about an ongoing
** online backup operation. ^The sqlite3_backup object is created by
@@ -5371,7 +5418,6 @@ typedef struct sqlite3_backup sqlite3_backup;
/*
** CAPI3REF: Online Backup API.
** EXPERIMENTAL
**
** The backup API copies the content of one database into another.
** It is useful either for creating backups of databases or
@@ -5440,10 +5486,14 @@ typedef struct sqlite3_backup sqlite3_backup;
** [SQLITE_NOMEM], [SQLITE_BUSY], [SQLITE_LOCKED], or an
** [SQLITE_IOERR_ACCESS | SQLITE_IOERR_XXX] extended error code.
**
** ^The sqlite3_backup_step() might return [SQLITE_READONLY] if the destination
** database was opened read-only or if
** the destination is an in-memory database with a different page size
** from the source database.
** ^(The sqlite3_backup_step() might return [SQLITE_READONLY] if
** <ol>
** <li> the destination database was opened read-only, or
** <li> the destination database is using write-ahead-log journaling
** and the destination and source page sizes differ, or
** <li> The destination database is an in-memory database and the
** destination and source page sizes differ.
** </ol>)^
**
** ^If sqlite3_backup_step() cannot obtain a required file-system lock, then
** the [sqlite3_busy_handler | busy-handler function]
@@ -5559,7 +5609,6 @@ int sqlite3_backup_pagecount(sqlite3_backup *p);
/*
** CAPI3REF: Unlock Notification
** EXPERIMENTAL
**
** ^When running in shared-cache mode, a database operation may fail with
** an [SQLITE_LOCKED] error if the required locks on the shared-cache or
@@ -5681,7 +5730,6 @@ int sqlite3_unlock_notify(
/*
** CAPI3REF: String Comparison
** EXPERIMENTAL
**
** ^The [sqlite3_strnicmp()] API allows applications and extensions to
** compare the contents of two buffers containing UTF-8 strings in a
@@ -5692,12 +5740,11 @@ int sqlite3_strnicmp(const char *, const char *, int);
/*
** CAPI3REF: Error Logging Interface
** EXPERIMENTAL
**
** ^The [sqlite3_log()] interface writes a message into the error log
** established by the [SQLITE_CONFIG_LOG] option to [sqlite3_config()].
** ^If logging is enabled, the zFormat string and subsequent arguments are
** passed through to [sqlite3_vmprintf()] to generate the final output string.
** used with [sqlite3_snprintf()] to generate the final output string.
**
** The sqlite3_log() interface is intended for use by extensions such as
** virtual tables, collating functions, and SQL functions. While there is
@@ -5714,6 +5761,86 @@ int sqlite3_strnicmp(const char *, const char *, int);
*/
void sqlite3_log(int iErrCode, const char *zFormat, ...);
/*
** CAPI3REF: Write-Ahead Log Commit Hook
**
** ^The [sqlite3_wal_hook()] function is used to register a callback that
** will be invoked each time a database connection commits data to a
** [write-ahead log] (i.e. whenever a transaction is committed in
** [journal_mode | journal_mode=WAL mode]).
**
** ^The callback is invoked by SQLite after the commit has taken place and
** the associated write-lock on the database released, so the implementation
** may read, write or [checkpoint] the database as required.
**
** ^The first parameter passed to the callback function when it is invoked
** is a copy of the third parameter passed to sqlite3_wal_hook() when
** registering the callback. ^The second is a copy of the database handle.
** ^The third parameter is the name of the database that was written to -
** either "main" or the name of an ATTACHed database. ^The fourth parameter
** is the number of pages currently in the write-ahead log file,
** including those that were just committed.
**
** The callback function should normally return SQLITE_OK. ^If an error
** code is returned, that error will propagate back up through the
** SQLite code base to cause the statement that provoked the callback
** to report an error, though the commit will have still occurred.
**
** A single database handle may have at most a single write-ahead log callback
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
** previously registered write-ahead log callback. Note that the
** [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
** those overwrite any prior [sqlite3_wal_hook()] settings.
*/
void *sqlite3_wal_hook(
sqlite3*,
int(*)(void *,sqlite3*,const char*,int),
void*
);
/*
** CAPI3REF: Configure an auto-checkpoint
**
** ^The [sqlite3_wal_autocheckpoint(D,N)] is a wrapper around
** [sqlite3_wal_hook()] that causes any database on [database connection] D
** to automatically [checkpoint]
** after committing a transaction if there are N or
** more frames in the [write-ahead log] file. ^Passing zero or
** a negative value as the nFrame parameter disables automatic
** checkpoints entirely.
**
** ^The callback registered by this function replaces any existing callback
** registered using [sqlite3_wal_hook()]. ^Likewise, registering a callback
** using [sqlite3_wal_hook()] disables the automatic checkpoint mechanism
** configured by this function.
**
** ^The [wal_autocheckpoint pragma] can be used to invoke this interface
** from SQL.
**
** ^Every new [database connection] defaults to having the auto-checkpoint
** enabled with a threshold of 1000 pages. The use of this interface
** is only necessary if the default setting is found to be suboptimal
** for a particular application.
*/
int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
/*
** CAPI3REF: Checkpoint a database
**
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
** empty string, then a checkpoint is run on all databases of
** connection D. ^If the database connection D is not in
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
**
** ^The [wal_checkpoint pragma] can be used to invoke this interface
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
** [wal_autocheckpoint pragma] can be used to cause this interface to be
** run whenever the WAL reaches a certain size threshold.
*/
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
/*
** Undo the hack that converts floating point types to integer for
** builds on processors without floating point support.
+61 -4
View File
@@ -92,7 +92,7 @@
** The correct "ANSI" way to do this is to use the intptr_t type.
** Unfortunately, that typedef is not available on all compilers, or
** if it is available, it requires an #include of specific headers
** that very from one machine to the next.
** that vary from one machine to the next.
**
** Ticket #3860: The llvm-gcc-4.2 compiler from Apple chokes on
** the ((void*)&((char*)0)[X]) construct. But MSVC chokes on ((void*)(X)).
@@ -301,6 +301,7 @@
*/
#ifdef SQLITE_OMIT_FLOATING_POINT
# define double sqlite_int64
# define float sqlite_int64
# define LONGDOUBLE_TYPE sqlite_int64
# ifndef SQLITE_BIG_DBL
# define SQLITE_BIG_DBL (((sqlite3_int64)1)<<50)
@@ -822,6 +823,10 @@ struct sqlite3 {
void (*xRollbackCallback)(void*); /* Invoked at every commit. */
void *pUpdateArg;
void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64);
#ifndef SQLITE_OMIT_WAL
int (*xWalCallback)(void *, sqlite3 *, const char *, int);
void *pWalArg;
#endif
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
@@ -911,6 +916,8 @@ struct sqlite3 {
#define SQLITE_ReverseOrder 0x01000000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x02000000 /* Enable recursive triggers */
#define SQLITE_ForeignKeys 0x04000000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x08000000 /* Enable automatic indexes */
#define SQLITE_PreferBuiltin 0x10000000 /* Preference to built-in funcs */
/*
** Bits of the sqlite3.flags field that are used by the
@@ -922,7 +929,8 @@ struct sqlite3 {
#define SQLITE_IndexSort 0x04 /* Disable indexes for sorting */
#define SQLITE_IndexSearch 0x08 /* Disable indexes for searching */
#define SQLITE_IndexCover 0x10 /* Disable index covering table */
#define SQLITE_OptMask 0x1f /* Mask of all disablable opts */
#define SQLITE_GroupByOrder 0x20 /* Disable GROUPBY cover of ORDERBY */
#define SQLITE_OptMask 0xff /* Mask of all disablable opts */
/*
** Possible values for the sqlite.magic field.
@@ -1773,6 +1781,9 @@ typedef u64 Bitmask;
** and the next table on the list. The parser builds the list this way.
** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
** jointype expresses the join between the table and the previous table.
**
** In the colUsed field, the high-order bit (bit 63) is set if the table
** contains more than 63 columns and the 64-th or later column is used.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -1884,7 +1895,7 @@ struct WhereLevel {
#define WHERE_ORDERBY_MAX 0x0002 /* ORDER BY processing for max() func */
#define WHERE_ONEPASS_DESIRED 0x0004 /* Want to do one-pass UPDATE/DELETE */
#define WHERE_DUPLICATES_OK 0x0008 /* Ok to return a row more than once */
#define WHERE_OMIT_OPEN 0x0010 /* Table cursor are already open */
#define WHERE_OMIT_OPEN 0x0010 /* Table cursors are already open */
#define WHERE_OMIT_CLOSE 0x0020 /* Omit close of table & index cursors */
#define WHERE_FORCE_TABLE 0x0040 /* Do not use an index-only search */
#define WHERE_ONETABLE_ONLY 0x0080 /* Only code the 1st table in pTabList */
@@ -1907,6 +1918,7 @@ struct WhereInfo {
int iBreak; /* Jump here to break out of the loop */
int nLevel; /* Number of nested loop */
struct WhereClause *pWC; /* Decomposition of the WHERE clause */
double savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */
WhereLevel a[1]; /* Information about each nest loop in WHERE */
};
@@ -2148,6 +2160,7 @@ struct Parse {
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
u8 disableTriggers; /* True to disable triggers */
double nQueryLoop; /* Estimated number of iterations of a query */
/* Above is constant between recursions. Below is reset before and after
** each recursion */
@@ -2524,6 +2537,7 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
#ifndef SQLITE_MUTEX_OMIT
sqlite3_mutex_methods *sqlite3DefaultMutex(void);
sqlite3_mutex_methods *sqlite3NoopMutex(void);
sqlite3_mutex *sqlite3MutexAlloc(int);
int sqlite3MutexInit(void);
int sqlite3MutexEnd(void);
@@ -2681,6 +2695,7 @@ void sqlite3Vacuum(Parse*);
int sqlite3RunVacuum(char**, sqlite3*);
char *sqlite3NameFromToken(sqlite3*, Token*);
int sqlite3ExprCompare(Expr*, Expr*);
int sqlite3ExprListCompare(ExprList*, ExprList*);
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
Vdbe *sqlite3GetVdbe(Parse*);
@@ -2874,7 +2889,7 @@ extern int sqlite3PendingByte;
#endif
void sqlite3RootPageMoved(Db*, int, int);
void sqlite3Reindex(Parse*, Token*, Token*);
void sqlite3AlterFunctions(sqlite3*);
void sqlite3AlterFunctions(void);
void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
int sqlite3GetToken(const unsigned char *, int *);
void sqlite3NestedParse(Parse*, const char*, ...);
@@ -2983,6 +2998,9 @@ void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
int sqlite3TempInMemory(const sqlite3*);
VTable *sqlite3GetVTable(sqlite3*, Table*);
const char *sqlite3JournalModename(int);
int sqlite3Checkpoint(sqlite3*, int);
int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
@@ -3089,4 +3107,43 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
# define sqlite3VdbeIOTraceSql(X)
#endif
/*
** These routines are available for the mem2.c debugging memory allocator
** only. They are used to verify that different "types" of memory
** allocations are properly tracked by the system.
**
** sqlite3MemdebugSetType() sets the "type" of an allocation to one of
** the MEMTYPE_* macros defined below. The type must be a bitmask with
** a single bit set.
**
** sqlite3MemdebugHasType() returns true if any of the bits in its second
** argument match the type set by the previous sqlite3MemdebugSetType().
** sqlite3MemdebugHasType() is intended for use inside assert() statements.
** For example:
**
** assert( sqlite3MemdebugHasType(p, MEMTYPE_HEAP) );
**
** Perhaps the most important point is the difference between MEMTYPE_HEAP
** and MEMTYPE_DB. If an allocation is MEMTYPE_DB, that means it might have
** been allocated by lookaside, except the allocation was too large or
** lookaside was already full. It is important to verify that allocations
** that might have been satisfied by lookaside are not passed back to
** non-lookaside free() routines. Asserts such as the example above are
** placed on the non-lookaside free() routines to verify this constraint.
**
** All of this is no-op for a production build. It only comes into
** play when the SQLITE_MEMDEBUG compile-time option is used.
*/
#ifdef SQLITE_MEMDEBUG
void sqlite3MemdebugSetType(void*,u8);
int sqlite3MemdebugHasType(void*,u8);
#else
# define sqlite3MemdebugSetType(X,Y) /* no-op */
# define sqlite3MemdebugHasType(X,Y) 1
#endif
#define MEMTYPE_HEAP 0x01 /* General heap allocations */
#define MEMTYPE_DB 0x02 /* Associated with a database connection */
#define MEMTYPE_SCRATCH 0x04 /* Scratch allocations */
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
#endif /* _SQLITEINT_H_ */
+8
View File
@@ -108,6 +108,14 @@
# define SQLITE_DEFAULT_TEMP_CACHE_SIZE 500
#endif
/*
** The default number of frames to accumulate in the log file before
** checkpointing the database in WAL mode.
*/
#ifndef SQLITE_DEFAULT_WAL_AUTOCHECKPOINT
# define SQLITE_DEFAULT_WAL_AUTOCHECKPOINT 1000
#endif
/*
** The maximum number of attached databases. This must be between 0
** and 30. The upper bound on 30 is because a 32-bit integer bitmap
+20
View File
@@ -112,6 +112,26 @@ int sqlite3_db_status(
}
break;
}
/*
** Return an approximation for the amount of memory currently used
** by all pagers associated with the given database connection. The
** highwater mark is meaningless and is returned as zero.
*/
case SQLITE_DBSTATUS_CACHE_USED: {
int totalUsed = 0;
int i;
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
Pager *pPager = sqlite3BtreePager(pBt);
totalUsed += sqlite3PagerMemUsed(pPager);
}
}
*pCurrent = totalUsed;
*pHighwater = 0;
break;
}
default: {
return SQLITE_ERROR;
}
+51 -5
View File
@@ -123,6 +123,7 @@ struct SqliteDb {
SqlFunc *pFunc; /* List of SQL functions */
Tcl_Obj *pUpdateHook; /* Update hook script (if any) */
Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */
Tcl_Obj *pWalHook; /* WAL hook script (if any) */
Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */
SqlCollate *pCollate; /* List of SQL collation functions */
int rc; /* Return code of most recent sqlite3_exec() */
@@ -132,7 +133,7 @@ struct SqliteDb {
int maxStmt; /* The next maximum number of stmtList */
int nStmt; /* Number of statements in stmtList */
IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
int nStep, nSort; /* Statistics for most recent operation */
int nStep, nSort, nIndex; /* Statistics for most recent operation */
int nTransaction; /* Number of nested [transaction] methods */
};
@@ -485,6 +486,9 @@ static void DbDeleteCmd(void *db){
if( pDb->pRollbackHook ){
Tcl_DecrRefCount(pDb->pRollbackHook);
}
if( pDb->pWalHook ){
Tcl_DecrRefCount(pDb->pWalHook);
}
if( pDb->pCollateNeeded ){
Tcl_DecrRefCount(pDb->pCollateNeeded);
}
@@ -589,6 +593,35 @@ static void DbRollbackHandler(void *clientData){
}
}
/*
** This procedure handles wal_hook callbacks.
*/
static int DbWalHandler(
void *clientData,
sqlite3 *db,
const char *zDb,
int nEntry
){
int ret = SQLITE_OK;
Tcl_Obj *p;
SqliteDb *pDb = (SqliteDb*)clientData;
Tcl_Interp *interp = pDb->interp;
assert(pDb->pWalHook);
p = Tcl_DuplicateObj(pDb->pWalHook);
Tcl_IncrRefCount(p);
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
){
Tcl_BackgroundError(interp);
}
Tcl_DecrRefCount(p);
return ret;
}
#if defined(SQLITE_TEST) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY)
static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){
char zBuf[64];
@@ -1351,6 +1384,7 @@ static int dbEvalStep(DbEvalContext *p){
pDb->nStep = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_FULLSCAN_STEP,1);
pDb->nSort = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_SORT,1);
pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
dbReleaseColumnNames(p);
p->pPreStmt = 0;
@@ -1544,7 +1578,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"restore", "rollback_hook", "status",
"timeout", "total_changes", "trace",
"transaction", "unlock_notify", "update_hook",
"version", 0
"version", "wal_hook", 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
@@ -1558,7 +1592,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS,
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK,
DB_VERSION,
DB_VERSION, DB_WAL_HOOK
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -2528,7 +2562,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
** $db status (step|sort)
** $db status (step|sort|autoindex)
**
** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
@@ -2545,8 +2579,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
v = pDb->nStep;
}else if( strcmp(zOp, "sort")==0 ){
v = pDb->nSort;
}else if( strcmp(zOp, "autoindex")==0 ){
v = pDb->nIndex;
}else{
Tcl_AppendResult(interp, "bad argument: should be step or sort",
Tcl_AppendResult(interp,
"bad argument: should be autoindex, step, or sort",
(char*)0);
return TCL_ERROR;
}
@@ -2726,9 +2763,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
** $db wal_hook ?script?
** $db update_hook ?script?
** $db rollback_hook ?script?
*/
case DB_WAL_HOOK:
case DB_UPDATE_HOOK:
case DB_ROLLBACK_HOOK: {
@@ -2738,6 +2777,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_Obj **ppHook;
if( choice==DB_UPDATE_HOOK ){
ppHook = &pDb->pUpdateHook;
}else if( choice==DB_WAL_HOOK ){
ppHook = &pDb->pWalHook;
}else{
ppHook = &pDb->pRollbackHook;
}
@@ -2763,6 +2804,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
sqlite3_update_hook(pDb->db, (pDb->pUpdateHook?DbUpdateHandler:0), pDb);
sqlite3_rollback_hook(pDb->db,(pDb->pRollbackHook?DbRollbackHandler:0),pDb);
sqlite3_wal_hook(pDb->db,(pDb->pWalHook?DbWalHandler:0),pDb);
break;
}
@@ -3477,6 +3519,7 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest9_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
extern int Sqlitetest_func_Init(Tcl_Interp*);
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
extern int Sqlitetest_init_Init(Tcl_Interp*);
@@ -3490,6 +3533,7 @@ int TCLSH_MAIN(int argc, char **argv){
extern int SqlitetestOsinst_Init(Tcl_Interp*);
extern int Sqlitetestbackup_Init(Tcl_Interp*);
extern int Sqlitetestintarray_Init(Tcl_Interp*);
extern int Sqlitetestvfs_Init(Tcl_Interp *);
Sqliteconfig_Init(interp);
Sqlitetest1_Init(interp);
@@ -3503,6 +3547,7 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetest9_Init(interp);
Sqlitetestasync_Init(interp);
Sqlitetest_autoext_Init(interp);
Sqlitetest_demovfs_Init(interp);
Sqlitetest_func_Init(interp);
Sqlitetest_hexio_Init(interp);
Sqlitetest_init_Init(interp);
@@ -3515,6 +3560,7 @@ int TCLSH_MAIN(int argc, char **argv){
SqlitetestOsinst_Init(interp);
Sqlitetestbackup_Init(interp);
Sqlitetestintarray_Init(interp);
Sqlitetestvfs_Init(interp);
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);
+31
View File
@@ -2025,6 +2025,7 @@ static int test_stmt_status(
} aOp[] = {
{ "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP },
{ "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT },
{ "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX },
};
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG");
@@ -4867,6 +4868,35 @@ static int test_unlock_notify(
}
#endif
/*
** tclcmd: sqlite3_wal_checkpoint db ?NAME?
*/
static int test_wal_checkpoint(
ClientData clientData, /* Unused */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
char *zDb = 0;
sqlite3 *db;
int rc;
if( objc!=3 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB ?NAME?");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
if( objc==3 ){
zDb = Tcl_GetString(objv[2]);
}
rc = sqlite3_wal_checkpoint(db, zDb);
Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
/*
** tcl_objproc COMMANDNAME ARGS...
@@ -5088,6 +5118,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
{ "sqlite3_unlock_notify", test_unlock_notify, 0 },
#endif
{ "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;
+1
View File
@@ -581,6 +581,7 @@ static int testPendingByte(
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PENDING-BYTE\"", (void*)0);
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[1], &pbyte) ) return TCL_ERROR;
rc = sqlite3_test_control(SQLITE_TESTCTRL_PENDING_BYTE, pbyte);
+36 -4
View File
@@ -520,8 +520,31 @@ static int cfDeviceCharacteristics(sqlite3_file *pFile){
return g.iDeviceCharacteristics;
}
/*
** Pass-throughs for WAL support.
*/
static int cfShmOpen(sqlite3_file *pFile){
return sqlite3OsShmOpen(((CrashFile*)pFile)->pRealFile);
}
static int cfShmSize(sqlite3_file *pFile, int reqSize, int *pNew){
return sqlite3OsShmSize(((CrashFile*)pFile)->pRealFile, reqSize, pNew);
}
static int cfShmGet(sqlite3_file *pFile, int reqSize, int *pSize, void **pp){
return sqlite3OsShmGet(((CrashFile*)pFile)->pRealFile, reqSize, pSize, pp);
}
static int cfShmRelease(sqlite3_file *pFile){
return sqlite3OsShmRelease(((CrashFile*)pFile)->pRealFile);
}
static int cfShmLock(sqlite3_file *pFile, int desired, int *pGot){
return sqlite3OsShmLock(((CrashFile*)pFile)->pRealFile, desired, pGot);
}
static int cfShmClose(sqlite3_file *pFile, int delFlag){
return sqlite3OsShmClose(((CrashFile*)pFile)->pRealFile, delFlag);
}
static const sqlite3_io_methods CrashFileVtab = {
1, /* iVersion */
2, /* iVersion */
cfClose, /* xClose */
cfRead, /* xRead */
cfWrite, /* xWrite */
@@ -533,7 +556,13 @@ static const sqlite3_io_methods CrashFileVtab = {
cfCheckReservedLock, /* xCheckReservedLock */
cfFileControl, /* xFileControl */
cfSectorSize, /* xSectorSize */
cfDeviceCharacteristics /* xDeviceCharacteristics */
cfDeviceCharacteristics, /* xDeviceCharacteristics */
cfShmOpen, /* xShmOpen */
cfShmSize, /* xShmSize */
cfShmGet, /* xShmGet */
cfShmRelease, /* xShmRelease */
cfShmLock, /* xShmLock */
cfShmClose /* xShmClose */
};
/*
@@ -764,7 +793,7 @@ static int crashEnableCmd(
){
int isEnable;
static sqlite3_vfs crashVfs = {
1, /* iVersion */
2, /* iVersion */
0, /* szOsFile */
0, /* mxPathname */
0, /* pNext */
@@ -781,7 +810,10 @@ static int crashEnableCmd(
cfDlClose, /* xDlClose */
cfRandomness, /* xRandomness */
cfSleep, /* xSleep */
cfCurrentTime /* xCurrentTime */
cfCurrentTime, /* xCurrentTime */
0, /* xGetlastError */
0, /* xRename */
0, /* xCurrentTimeInt64 */
};
if( objc!=2 ){
+12
View File
@@ -127,6 +127,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "autoinc", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTOMATIC_INDEX
Tcl_SetVar2(interp, "sqlite_options", "autoindex", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "autoindex", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_AUTOVACUUM
Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY);
#else
@@ -493,6 +499,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_WAL
Tcl_SetVar2(interp, "sqlite_options", "wal", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "wal", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_WSD
Tcl_SetVar2(interp, "sqlite_options", "wsd", "0", TCL_GLOBAL_ONLY);
#else
+671
View File
@@ -0,0 +1,671 @@
/*
** 2010 April 7
**
** 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.
**
*************************************************************************
**
** An example of a simple VFS implementation that omits complex features
** often not required or not possible on embedded platforms. Also includes
** code to buffer writes to the journal file, which can be a significant
** performance improvement on some embedded platforms.
**
*/
/*
** OVERVIEW
**
** The code in this file implements a minimal SQLite VFS that can be
** used on Linux and other posix-like operating systems. The following
** system calls are used:
**
** File-system: access(), unlink(), getcwd()
** File IO: open(), read(), write(), fsync(), close(), fstat()
** Other: sleep(), usleep(), time()
**
** The following VFS features are omitted:
**
** 1. File locking. The user must ensure that there is at most one
** connection to each database when using this VFS. Multiple
** connections to a single shared-cache count as a single connection
** for the purposes of the previous statement.
**
** 2. The loading of dynamic extensions (shared libraries).
**
** 3. Temporary files. The user must configure SQLite to use in-memory
** temp files when using this VFS. The easiest way to do this is to
** compile with:
**
** -DSQLITE_TEMP_STORE=3
**
** 4. File truncation. As of version 3.6.24, SQLite may run without
** a working xTruncate() call, providing the user does not configure
** SQLite to use "journal_mode=truncate", or use both
** "journal_mode=persist" and ATTACHed databases.
**
** It is assumed that the system uses UNIX-like path-names. Specifically,
** that '/' characters are used to separate path components and that
** a path-name is a relative path unless it begins with a '/'. And that
** no UTF-8 encoded paths are greater than 512 bytes in length.
**
** JOURNAL WRITE-BUFFERING
**
** To commit a transaction to the database, SQLite first writes rollback
** information into the journal file. This usually consists of 4 steps:
**
** 1. The rollback information is sequentially written into the journal
** file, starting at the start of the file.
** 2. The journal file is synced to disk.
** 3. A modification is made to the first few bytes of the journal file.
** 4. The journal file is synced to disk again.
**
** Most of the data is written in step 1 using a series of calls to the
** VFS xWrite() method. The buffers passed to the xWrite() calls are of
** various sizes. For example, as of version 3.6.24, when committing a
** transaction that modifies 3 pages of a database file that uses 4096
** byte pages residing on a media with 512 byte sectors, SQLite makes
** eleven calls to the xWrite() method to create the rollback journal,
** as follows:
**
** Write offset | Bytes written
** ----------------------------
** 0 512
** 512 4
** 516 4096
** 4612 4
** 4616 4
** 4620 4096
** 8716 4
** 8720 4
** 8724 4096
** 12820 4
** ++++++++++++SYNC+++++++++++
** 0 12
** ++++++++++++SYNC+++++++++++
**
** On many operating systems, this is an efficient way to write to a file.
** However, on some embedded systems that do not cache writes in OS
** buffers it is much more efficient to write data in blocks that are
** an integer multiple of the sector-size in size and aligned at the
** start of a sector.
**
** To work around this, the code in this file allocates a fixed size
** buffer of SQLITE_DEMOVFS_BUFFERSZ using sqlite3_malloc() whenever a
** journal file is opened. It uses the buffer to coalesce sequential
** writes into aligned SQLITE_DEMOVFS_BUFFERSZ blocks. When SQLite
** invokes the xSync() method to sync the contents of the file to disk,
** all accumulated data is written out, even if it does not constitute
** a complete block. This means the actual IO to create the rollback
** journal for the example transaction above is this:
**
** Write offset | Bytes written
** ----------------------------
** 0 8192
** 8192 4632
** ++++++++++++SYNC+++++++++++
** 0 12
** ++++++++++++SYNC+++++++++++
**
** Much more efficient if the underlying OS is not caching write
** operations.
*/
#if !defined(SQLITE_TEST) || defined(SQLITE_OS_UNIX)
#include <sqlite3.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/param.h>
#include <unistd.h>
#include <time.h>
/*
** Size of the write buffer used by journal files in bytes.
*/
#ifndef SQLITE_DEMOVFS_BUFFERSZ
# define SQLITE_DEMOVFS_BUFFERSZ 8192
#endif
/*
** When using this VFS, the sqlite3_file* handles that SQLite uses are
** actually pointers to instances of type DemoFile.
*/
typedef struct DemoFile DemoFile;
struct DemoFile {
sqlite3_file base; /* Base class. Must be first. */
int fd; /* File descriptor */
char *aBuffer; /* Pointer to malloc'd buffer */
int nBuffer; /* Valid bytes of data in zBuffer */
sqlite3_int64 iBufferOfst; /* Offset in file of zBuffer[0] */
};
/*
** Write directly to the file passed as the first argument. Even if the
** file has a write-buffer (DemoFile.aBuffer), ignore it.
*/
static int demoDirectWrite(
DemoFile *p, /* File handle */
const void *zBuf, /* Buffer containing data to write */
int iAmt, /* Size of data to write in bytes */
sqlite_int64 iOfst /* File offset to write to */
){
off_t ofst; /* Return value from lseek() */
size_t nWrite; /* Return value from write() */
ofst = lseek(p->fd, iOfst, SEEK_SET);
if( ofst!=iOfst ){
return SQLITE_IOERR_WRITE;
}
nWrite = write(p->fd, zBuf, iAmt);
if( nWrite!=iAmt ){
return SQLITE_IOERR_WRITE;
}
return SQLITE_OK;
}
/*
** Flush the contents of the DemoFile.aBuffer buffer to disk. This is a
** no-op if this particular file does not have a buffer (i.e. it is not
** a journal file) or if the buffer is currently empty.
*/
static int demoFlushBuffer(DemoFile *p){
int rc = SQLITE_OK;
if( p->nBuffer ){
rc = demoDirectWrite(p, p->aBuffer, p->nBuffer, p->iBufferOfst);
p->nBuffer = 0;
}
return rc;
}
/*
** Close a file.
*/
static int demoClose(sqlite3_file *pFile){
int rc;
DemoFile *p = (DemoFile*)pFile;
rc = demoFlushBuffer(p);
sqlite3_free(p->aBuffer);
close(p->fd);
return rc;
}
/*
** Read data from a file.
*/
static int demoRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
DemoFile *p = (DemoFile*)pFile;
off_t ofst; /* Return value from lseek() */
int nRead; /* Return value from read() */
int rc; /* Return code from demoFlushBuffer() */
/* Flush any data in the write buffer to disk in case this operation
** is trying to read data the file-region currently cached in the buffer.
** It would be possible to detect this case and possibly save an
** unnecessary write here, but in practice SQLite will rarely read from
** a journal file when there is data cached in the write-buffer.
*/
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
ofst = lseek(p->fd, iOfst, SEEK_SET);
if( ofst!=iOfst ){
return SQLITE_IOERR_READ;
}
nRead = read(p->fd, zBuf, iAmt);
if( nRead==iAmt ){
return SQLITE_OK;
}else if( nRead>=0 ){
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_IOERR_READ;
}
/*
** Write data to a crash-file.
*/
static int demoWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
DemoFile *p = (DemoFile*)pFile;
if( p->aBuffer ){
char *z = (char *)zBuf; /* Pointer to remaining data to write */
int n = iAmt; /* Number of bytes at z */
sqlite3_int64 i = iOfst; /* File offset to write to */
while( n>0 ){
int nCopy; /* Number of bytes to copy into buffer */
/* If the buffer is full, or if this data is not being written directly
** following the data already buffered, flush the buffer. Flushing
** the buffer is a no-op if it is empty.
*/
if( p->nBuffer==SQLITE_DEMOVFS_BUFFERSZ || p->iBufferOfst+p->nBuffer!=i ){
int rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
}
assert( p->nBuffer==0 || p->iBufferOfst+p->nBuffer==i );
p->iBufferOfst = i - p->nBuffer;
/* Copy as much data as possible into the buffer. */
nCopy = SQLITE_DEMOVFS_BUFFERSZ - p->nBuffer;
if( nCopy>n ){
nCopy = n;
}
memcpy(&p->aBuffer[p->nBuffer], z, nCopy);
p->nBuffer += nCopy;
n -= nCopy;
i += nCopy;
z += nCopy;
}
}else{
return demoDirectWrite(p, zBuf, iAmt, iOfst);
}
return SQLITE_OK;
}
/*
** Truncate a file. This is a no-op for this VFS (see header comments at
** the top of the file).
*/
static int demoTruncate(sqlite3_file *pFile, sqlite_int64 size){
#if 0
if( ftruncate(((DemoFile *)pFile)->fd, size) ) return SQLITE_IOERR_TRUNCATE;
#endif
return SQLITE_OK;
}
/*
** Sync the contents of the file to the persistent media.
*/
static int demoSync(sqlite3_file *pFile, int flags){
DemoFile *p = (DemoFile*)pFile;
int rc;
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
rc = fsync(p->fd);
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_FSYNC);
}
/*
** Write the size of the file in bytes to *pSize.
*/
static int demoFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
DemoFile *p = (DemoFile*)pFile;
int rc; /* Return code from fstat() call */
struct stat sStat; /* Output of fstat() call */
/* Flush the contents of the buffer to disk. As with the flush in the
** demoRead() method, it would be possible to avoid this and save a write
** here and there. But in practice this comes up so infrequently it is
** not worth the trouble.
*/
rc = demoFlushBuffer(p);
if( rc!=SQLITE_OK ){
return rc;
}
rc = fstat(p->fd, &sStat);
if( rc!=0 ) return SQLITE_IOERR_FSTAT;
*pSize = sStat.st_size;
return SQLITE_OK;
}
/*
** Locking functions. The xLock() and xUnlock() methods are both no-ops.
** The xCheckReservedLock() always indicates that no other process holds
** a reserved lock on the database file. This ensures that if a hot-journal
** file is found in the file-system it is rolled back.
*/
static int demoLock(sqlite3_file *pFile, int eLock){
return SQLITE_OK;
}
static int demoUnlock(sqlite3_file *pFile, int eLock){
return SQLITE_OK;
}
static int demoCheckReservedLock(sqlite3_file *pFile, int *pResOut){
*pResOut = 0;
return SQLITE_OK;
}
/*
** No xFileControl() verbs are implemented by this VFS.
*/
static int demoFileControl(sqlite3_file *pFile, int op, void *pArg){
return SQLITE_OK;
}
/*
** The xSectorSize() and xDeviceCharacteristics() methods. These two
** may return special values allowing SQLite to optimize file-system
** access to some extent. But it is also safe to simply return 0.
*/
static int demoSectorSize(sqlite3_file *pFile){
return 0;
}
static int demoDeviceCharacteristics(sqlite3_file *pFile){
return 0;
}
/*
** Open a file handle.
*/
static int demoOpen(
sqlite3_vfs *pVfs, /* VFS */
const char *zName, /* File to open, or 0 for a temp file */
sqlite3_file *pFile, /* Pointer to DemoFile struct to populate */
int flags, /* Input SQLITE_OPEN_XXX flags */
int *pOutFlags /* Output SQLITE_OPEN_XXX flags (or NULL) */
){
static const sqlite3_io_methods demoio = {
1, /* iVersion */
demoClose, /* xClose */
demoRead, /* xRead */
demoWrite, /* xWrite */
demoTruncate, /* xTruncate */
demoSync, /* xSync */
demoFileSize, /* xFileSize */
demoLock, /* xLock */
demoUnlock, /* xUnlock */
demoCheckReservedLock, /* xCheckReservedLock */
demoFileControl, /* xFileControl */
demoSectorSize, /* xSectorSize */
demoDeviceCharacteristics /* xDeviceCharacteristics */
};
DemoFile *p = (DemoFile*)pFile; /* Populate this structure */
int oflags = 0; /* flags to pass to open() call */
char *aBuf = 0;
if( zName==0 ){
return SQLITE_IOERR;
}
if( flags&SQLITE_OPEN_MAIN_JOURNAL ){
aBuf = (char *)sqlite3_malloc(SQLITE_DEMOVFS_BUFFERSZ);
if( !aBuf ){
return SQLITE_NOMEM;
}
}
if( flags&SQLITE_OPEN_EXCLUSIVE ) oflags |= O_EXCL;
if( flags&SQLITE_OPEN_CREATE ) oflags |= O_CREAT;
if( flags&SQLITE_OPEN_READONLY ) oflags |= O_RDONLY;
if( flags&SQLITE_OPEN_READWRITE ) oflags |= O_RDWR;
memset(p, 0, sizeof(DemoFile));
p->fd = open(zName, oflags, 0600);
if( p->fd<0 ){
sqlite3_free(aBuf);
return SQLITE_CANTOPEN;
}
p->aBuffer = aBuf;
if( pOutFlags ){
*pOutFlags = flags;
}
p->base.pMethods = &demoio;
return SQLITE_OK;
}
/*
** Delete the file identified by argument zPath. If the dirSync parameter
** is non-zero, then ensure the file-system modification to delete the
** file has been synced to disk before returning.
*/
static int demoDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
int rc;
rc = unlink(zPath);
if( rc==0 && dirSync ){
int dfd; /* File descriptor open on directory */
int i; /* Iterator variable */
char zDir[pVfs->mxPathname+1];/* Name of directory containing file zPath */
/* Figure out the directory name from the path of the file deleted. */
sqlite3_snprintf(pVfs->mxPathname, zDir, "%s", zPath);
zDir[pVfs->mxPathname] = '\0';
for(i=strlen(zDir); i>1 && zDir[i]!='/'; i++);
zDir[i] = '\0';
/* Open a file-descriptor on the directory. Sync. Close. */
dfd = open(zDir, O_RDONLY, 0);
if( dfd<0 ){
rc = -1;
}else{
rc = fsync(dfd);
close(dfd);
}
}
return (rc==0 ? SQLITE_OK : SQLITE_IOERR_DELETE);
}
#ifndef F_OK
# define F_OK 0
#endif
#ifndef R_OK
# define R_OK 4
#endif
#ifndef W_OK
# define W_OK 2
#endif
/*
** Query the file-system to see if the named file exists, is readable or
** is both readable and writable.
*/
static int demoAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
int rc; /* access() return code */
int eAccess = F_OK; /* Second argument to access() */
assert( flags==SQLITE_ACCESS_EXISTS /* access(zPath, F_OK) */
|| flags==SQLITE_ACCESS_READ /* access(zPath, R_OK) */
|| flags==SQLITE_ACCESS_READWRITE /* access(zPath, R_OK|W_OK) */
);
if( flags==SQLITE_ACCESS_READWRITE ) eAccess = R_OK|W_OK;
if( flags==SQLITE_ACCESS_READ ) eAccess = R_OK;
rc = access(zPath, eAccess);
*pResOut = (rc==0);
return SQLITE_OK;
}
/*
** Argument zPath points to a nul-terminated string containing a file path.
** If zPath is an absolute path, then it is copied as is into the output
** buffer. Otherwise, if it is a relative path, then the equivalent full
** path is written to the output buffer.
**
** This function assumes that paths are UNIX style. Specifically, that:
**
** 1. Path components are separated by a '/'. and
** 2. Full paths begin with a '/' character.
*/
static int demoFullPathname(
sqlite3_vfs *pVfs, /* VFS */
const char *zPath, /* Input path (possibly a relative path) */
int nPathOut, /* Size of output buffer in bytes */
char *zPathOut /* Pointer to output buffer */
){
char zDir[pVfs->mxPathname+1];
if( zPath[0]=='/' ){
zDir[0] = '\0';
}else{
getcwd(zDir, sizeof(zDir));
}
zDir[pVfs->mxPathname] = '\0';
sqlite3_snprintf(nPathOut, zPathOut, "%s/%s", zDir, zPath);
zPathOut[nPathOut-1] = '\0';
return SQLITE_OK;
}
/*
** The following four VFS methods:
**
** xDlOpen
** xDlError
** xDlSym
** xDlClose
**
** are supposed to implement the functionality needed by SQLite to load
** extensions compiled as shared objects. This simple VFS does not support
** this functionality, so the following functions are no-ops.
*/
static void *demoDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return 0;
}
static void demoDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
sqlite3_snprintf(nByte, zErrMsg, "Loadable extensions are not supported");
zErrMsg[nByte-1] = '\0';
}
static void (*demoDlSym(sqlite3_vfs *pVfs, void *pH, const char *z))(void){
return 0;
}
static void demoDlClose(sqlite3_vfs *pVfs, void *pHandle){
return;
}
/*
** Parameter zByte points to a buffer nByte bytes in size. Populate this
** buffer with pseudo-random data.
*/
static int demoRandomness(sqlite3_vfs *pVfs, int nByte, char *zByte){
return SQLITE_OK;
}
/*
** Sleep for at least nMicro microseconds. Return the (approximate) number
** of microseconds slept for.
*/
static int demoSleep(sqlite3_vfs *pVfs, int nMicro){
sleep(nMicro / 1000000);
usleep(nMicro % 1000000);
return nMicro;
}
/*
** Set *pTime to the current UTC time expressed as a Julian day. Return
** SQLITE_OK if successful, or an error code otherwise.
**
** http://en.wikipedia.org/wiki/Julian_day
**
** This implementation is not very good. The current time is rounded to
** an integer number of seconds. Also, assuming time_t is a signed 32-bit
** value, it will stop working some time in the year 2038 AD (the so-called
** "year 2038" problem that afflicts systems that store time this way).
*/
static int demoCurrentTime(sqlite3_vfs *pVfs, double *pTime){
time_t t = time(0);
*pTime = t/86400.0 + 2440587.5;
return SQLITE_OK;
}
/*
** This function returns a pointer to the VFS implemented in this file.
** To make the VFS available to SQLite:
**
** sqlite3_vfs_register(sqlite3_demovfs(), 0);
*/
sqlite3_vfs *sqlite3_demovfs(void){
static sqlite3_vfs demovfs = {
1, /* iVersion */
sizeof(DemoFile), /* szOsFile */
512, /* mxPathname */
0, /* pNext */
"demo", /* zName */
0, /* pAppData */
demoOpen, /* xOpen */
demoDelete, /* xDelete */
demoAccess, /* xAccess */
demoFullPathname, /* xFullPathname */
demoDlOpen, /* xDlOpen */
demoDlError, /* xDlError */
demoDlSym, /* xDlSym */
demoDlClose, /* xDlClose */
demoRandomness, /* xRandomness */
demoSleep, /* xSleep */
demoCurrentTime, /* xCurrentTime */
};
return &demovfs;
}
#endif /* !defined(SQLITE_TEST) || defined(SQLITE_OS_UNIX) */
#ifdef SQLITE_TEST
#include <tcl.h>
#ifdef SQLITE_OS_UNIX
static int register_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3_vfs_register(sqlite3_demovfs(), 1);
return TCL_OK;
}
static int unregister_demovfs(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3_vfs_unregister(sqlite3_demovfs());
return TCL_OK;
}
/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "register_demovfs", register_demovfs, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_demovfs", unregister_demovfs, 0, 0);
return TCL_OK;
}
#else
int Sqlitetest_demovfs_Init(Tcl_Interp *interp){ return TCL_OK; }
#endif
#endif /* SQLITE_TEST */
+55 -5
View File
@@ -50,6 +50,12 @@ static int devsymCheckReservedLock(sqlite3_file*, int *);
static int devsymFileControl(sqlite3_file*, int op, void *pArg);
static int devsymSectorSize(sqlite3_file*);
static int devsymDeviceCharacteristics(sqlite3_file*);
static int devsymShmOpen(sqlite3_file*);
static int devsymShmSize(sqlite3_file*,int,int*);
static int devsymShmGet(sqlite3_file*,int,int*,void**);
static int devsymShmRelease(sqlite3_file*);
static int devsymShmLock(sqlite3_file*,int,int*);
static int devsymShmClose(sqlite3_file*,int);
/*
** Method declarations for devsym_vfs.
@@ -69,7 +75,7 @@ static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
static sqlite3_vfs devsym_vfs = {
1, /* iVersion */
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
@@ -92,11 +98,14 @@ static sqlite3_vfs devsym_vfs = {
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime /* xCurrentTime */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0, /* xRename */
0 /* xCurrentTimeInt64 */
};
static sqlite3_io_methods devsym_io_methods = {
1, /* iVersion */
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
@@ -108,7 +117,13 @@ static sqlite3_io_methods devsym_io_methods = {
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics /* xDeviceCharacteristics */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmOpen, /* xShmOpen */
devsymShmSize, /* xShmSize */
devsymShmGet, /* xShmGet */
devsymShmRelease, /* xShmRelease */
devsymShmLock, /* xShmLock */
devsymShmClose /* xShmClose */
};
struct DevsymGlobal {
@@ -222,6 +237,36 @@ static int devsymDeviceCharacteristics(sqlite3_file *pFile){
return g.iDeviceChar;
}
/*
** Shared-memory methods are all pass-thrus.
*/
static int devsymShmOpen(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmOpen(p->pReal);
}
static int devsymShmSize(sqlite3_file *pFile, int reqSize, int *pSize){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmSize(p->pReal, reqSize, pSize);
}
static int devsymShmGet(sqlite3_file *pFile, int reqSz, int *pSize, void **pp){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmGet(p->pReal, reqSz, pSize, pp);
}
static int devsymShmRelease(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmRelease(p->pReal);
}
static int devsymShmLock(sqlite3_file *pFile, int desired, int *pGot){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmLock(p->pReal, desired, pGot);
}
static int devsymShmClose(sqlite3_file *pFile, int delFlag){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsShmClose(p->pReal, delFlag);
}
/*
** Open an devsym file handle.
*/
@@ -330,9 +375,10 @@ static int devsymSleep(sqlite3_vfs *pVfs, int nMicro){
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return sqlite3OsCurrentTime(g.pVfs, pTimeOut);
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
** true, the devsym vfs becomes the new default vfs. It is the only publicly
@@ -346,9 +392,13 @@ void devsym_register(int iDeviceChar, int iSectorSize){
}
if( iDeviceChar>=0 ){
g.iDeviceChar = iDeviceChar;
}else{
g.iDeviceChar = 0;
}
if( iSectorSize>=0 ){
g.iSectorSize = iSectorSize;
}else{
g.iSectorSize = 512;
}
}
+2 -2
View File
@@ -179,7 +179,7 @@ static sqlite3_vfs jt_vfs = {
jtDlClose, /* xDlClose */
jtRandomness, /* xRandomness */
jtSleep, /* xSleep */
jtCurrentTime /* xCurrentTime */
jtCurrentTime, /* xCurrentTime */
};
static sqlite3_io_methods jt_io_methods = {
@@ -801,7 +801,7 @@ static int jtSleep(sqlite3_vfs *pVfs, int nMicro){
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int jtCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return sqlite3OsCurrentTime(g.pVfs, pTimeOut);
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
/**************************************************************************
+1
View File
@@ -1287,6 +1287,7 @@ static int test_db_status(
int op;
} aOp[] = {
{ "SQLITE_DBSTATUS_LOOKASIDE_USED", SQLITE_DBSTATUS_LOOKASIDE_USED },
{ "SQLITE_DBSTATUS_CACHE_USED", SQLITE_DBSTATUS_CACHE_USED },
};
Tcl_Obj *pResult;
if( objc!=4 ){
+15 -3
View File
@@ -198,7 +198,9 @@ static fs_vfs_t fs_vfs = {
fsDlClose, /* xDlClose */
fsRandomness, /* xRandomness */
fsSleep, /* xSleep */
fsCurrentTime /* xCurrentTime */
fsCurrentTime, /* xCurrentTime */
0, /* xRename */
0 /* xCurrentTimeInt64 */
},
0, /* pFileList */
0 /* pParent */
@@ -217,7 +219,12 @@ static sqlite3_io_methods fs_io_methods = {
fsCheckReservedLock, /* xCheckReservedLock */
fsFileControl, /* xFileControl */
fsSectorSize, /* xSectorSize */
fsDeviceCharacteristics /* xDeviceCharacteristics */
fsDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmOpen */
0, /* xShmSize */
0, /* xShmLock */
0, /* xShmClose */
0, /* xShmDelete */
};
@@ -234,7 +241,12 @@ static sqlite3_io_methods tmp_io_methods = {
tmpCheckReservedLock, /* xCheckReservedLock */
tmpFileControl, /* xFileControl */
tmpSectorSize, /* xSectorSize */
tmpDeviceCharacteristics /* xDeviceCharacteristics */
tmpDeviceCharacteristics, /* xDeviceCharacteristics */
0, /* xShmOpen */
0, /* xShmSize */
0, /* xShmLock */
0, /* xShmClose */
0, /* xShmDelete */
};
/* Useful macros used in several places */
+1 -1
View File
@@ -203,7 +203,7 @@ static sqlite3_vfs inst_vfs = {
instDlClose, /* xDlClose */
instRandomness, /* xRandomness */
instSleep, /* xSleep */
instCurrentTime /* xCurrentTime */
instCurrentTime, /* xCurrentTime */
};
static sqlite3_io_methods inst_io_methods = {
+2
View File
@@ -58,6 +58,7 @@ static Tcl_ObjCmdProc blocking_step_proc;
static Tcl_ObjCmdProc blocking_prepare_v2_proc;
#endif
int Sqlitetest1_Init(Tcl_Interp *);
int Sqlite3_Init(Tcl_Interp *);
/* Functions from test1.c */
void *sqlite3TestTextToPtr(const char *);
@@ -124,6 +125,7 @@ static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
#endif
Sqlitetest1_Init(interp);
Sqlitetest_mutex_Init(interp);
Sqlite3_Init(interp);
rc = Tcl_Eval(interp, p->zScript);
pRes = Tcl_GetObjResult(interp);
+808
View File
@@ -0,0 +1,808 @@
/*
** 2010 May 05
**
** 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.
**
******************************************************************************
**
*/
#if SQLITE_TEST /* This file is used for testing only */
#include "sqlite3.h"
#include "sqliteInt.h"
typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;
typedef struct TestvfsBuffer TestvfsBuffer;
typedef struct TestvfsFile TestvfsFile;
/*
** An open file handle.
*/
struct TestvfsFile {
sqlite3_file base; /* Base class. Must be first */
sqlite3_vfs *pVfs; /* The VFS */
const char *zFilename; /* Filename as passed to xOpen() */
sqlite3_file *pReal; /* The real, underlying file descriptor */
Tcl_Obj *pShmId; /* Shared memory id for Tcl callbacks */
TestvfsBuffer *pShm; /* Shared memory buffer */
};
/*
** An instance of this structure is allocated for each VFS created. The
** sqlite3_vfs.pAppData field of the VFS structure registered with SQLite
** is set to point to it.
*/
struct Testvfs {
char *zName; /* Name of this VFS */
sqlite3_vfs *pParent; /* The VFS to use for file IO */
sqlite3_vfs *pVfs; /* The testvfs registered with SQLite */
Tcl_Interp *interp; /* Interpreter to run script in */
int nScript; /* Number of elements in array apScript */
Tcl_Obj **apScript; /* Script to execute */
TestvfsBuffer *pBuffer; /* List of shared buffers */
int isNoshm;
};
/*
** A shared-memory buffer.
*/
struct TestvfsBuffer {
char *zFile; /* Associated file name */
int n; /* Size of allocated buffer in bytes */
u8 *a; /* Buffer allocated using ckalloc() */
int nRef; /* Number of references to this object */
TestvfsBuffer *pNext; /* Next in linked list of all buffers */
};
#define PARENTVFS(x) (((Testvfs *)((x)->pAppData))->pParent)
/*
** Method declarations for TestvfsFile.
*/
static int tvfsClose(sqlite3_file*);
static int tvfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
static int tvfsWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
static int tvfsTruncate(sqlite3_file*, sqlite3_int64 size);
static int tvfsSync(sqlite3_file*, int flags);
static int tvfsFileSize(sqlite3_file*, sqlite3_int64 *pSize);
static int tvfsLock(sqlite3_file*, int);
static int tvfsUnlock(sqlite3_file*, int);
static int tvfsCheckReservedLock(sqlite3_file*, int *);
static int tvfsFileControl(sqlite3_file*, int op, void *pArg);
static int tvfsSectorSize(sqlite3_file*);
static int tvfsDeviceCharacteristics(sqlite3_file*);
/*
** Method declarations for tvfs_vfs.
*/
static int tvfsOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
static int tvfsDelete(sqlite3_vfs*, const char *zName, int syncDir);
static int tvfsAccess(sqlite3_vfs*, const char *zName, int flags, int *);
static int tvfsFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
static void *tvfsDlOpen(sqlite3_vfs*, const char *zFilename);
static void tvfsDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
static void (*tvfsDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
static void tvfsDlClose(sqlite3_vfs*, void*);
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
static int tvfsRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int tvfsSleep(sqlite3_vfs*, int microseconds);
static int tvfsCurrentTime(sqlite3_vfs*, double*);
static int tvfsShmOpen(sqlite3_file*);
static int tvfsShmSize(sqlite3_file*, int , int *);
static int tvfsShmGet(sqlite3_file*, int , int *, void **);
static int tvfsShmRelease(sqlite3_file*);
static int tvfsShmLock(sqlite3_file*, int , int *);
static int tvfsShmClose(sqlite3_file*, int);
static sqlite3_io_methods tvfs_io_methods = {
2, /* iVersion */
tvfsClose, /* xClose */
tvfsRead, /* xRead */
tvfsWrite, /* xWrite */
tvfsTruncate, /* xTruncate */
tvfsSync, /* xSync */
tvfsFileSize, /* xFileSize */
tvfsLock, /* xLock */
tvfsUnlock, /* xUnlock */
tvfsCheckReservedLock, /* xCheckReservedLock */
tvfsFileControl, /* xFileControl */
tvfsSectorSize, /* xSectorSize */
tvfsDeviceCharacteristics, /* xDeviceCharacteristics */
tvfsShmOpen, /* xShmOpen */
tvfsShmSize, /* xShmSize */
tvfsShmGet, /* xShmGet */
tvfsShmRelease, /* xShmRelease */
tvfsShmLock, /* xShmLock */
tvfsShmClose /* xShmClose */
};
/*
** Close an tvfs-file.
*/
static int tvfsClose(sqlite3_file *pFile){
TestvfsFile *p = (TestvfsFile *)pFile;
if( p->pShmId ){
Tcl_DecrRefCount(p->pShmId);
p->pShmId = 0;
}
if( pFile->pMethods ){
ckfree((char *)pFile->pMethods);
}
return sqlite3OsClose(p->pReal);
}
/*
** Read data from an tvfs-file.
*/
static int tvfsRead(
sqlite3_file *pFile,
void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Write data to an tvfs-file.
*/
static int tvfsWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Truncate an tvfs-file.
*/
static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsTruncate(p->pReal, size);
}
/*
** Sync an tvfs-file.
*/
static int tvfsSync(sqlite3_file *pFile, int flags){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsSync(p->pReal, flags);
}
/*
** Return the current file-size of an tvfs-file.
*/
static int tvfsFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsFileSize(p->pReal, pSize);
}
/*
** Lock an tvfs-file.
*/
static int tvfsLock(sqlite3_file *pFile, int eLock){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsLock(p->pReal, eLock);
}
/*
** Unlock an tvfs-file.
*/
static int tvfsUnlock(sqlite3_file *pFile, int eLock){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsUnlock(p->pReal, eLock);
}
/*
** Check if another file-handle holds a RESERVED lock on an tvfs-file.
*/
static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsCheckReservedLock(p->pReal, pResOut);
}
/*
** File control method. For custom operations on an tvfs-file.
*/
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsFileControl(p->pReal, op, pArg);
}
/*
** Return the sector-size in bytes for an tvfs-file.
*/
static int tvfsSectorSize(sqlite3_file *pFile){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsSectorSize(p->pReal);
}
/*
** Return the device characteristic flags supported by an tvfs-file.
*/
static int tvfsDeviceCharacteristics(sqlite3_file *pFile){
TestvfsFile *p = (TestvfsFile *)pFile;
return sqlite3OsDeviceCharacteristics(p->pReal);
}
/*
** Open an tvfs file handle.
*/
static int tvfsOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
int rc;
TestvfsFile *p = (TestvfsFile *)pFile;
p->pShm = 0;
p->pShmId = 0;
p->zFilename = zName;
p->pVfs = pVfs;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(PARENTVFS(pVfs), zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
sqlite3_io_methods *pMethods;
pMethods = (sqlite3_io_methods *)ckalloc(sizeof(sqlite3_io_methods));
memcpy(pMethods, &tvfs_io_methods, sizeof(sqlite3_io_methods));
if( ((Testvfs *)pVfs->pAppData)->isNoshm ){
pMethods->xShmOpen = 0;
pMethods->xShmGet = 0;
pMethods->xShmSize = 0;
pMethods->xShmRelease = 0;
pMethods->xShmClose = 0;
pMethods->xShmLock = 0;
}
pFile->pMethods = pMethods;
}
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 tvfsDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
return sqlite3OsDelete(PARENTVFS(pVfs), zPath, dirSync);
}
/*
** Test for access permissions. Return true if the requested permission
** is available, or false otherwise.
*/
static int tvfsAccess(
sqlite3_vfs *pVfs,
const char *zPath,
int flags,
int *pResOut
){
return sqlite3OsAccess(PARENTVFS(pVfs), zPath, flags, pResOut);
}
/*
** 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 tvfsFullPathname(
sqlite3_vfs *pVfs,
const char *zPath,
int nOut,
char *zOut
){
return sqlite3OsFullPathname(PARENTVFS(pVfs), zPath, nOut, zOut);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
/*
** Open the dynamic library located at zPath and return a handle.
*/
static void *tvfsDlOpen(sqlite3_vfs *pVfs, const char *zPath){
return sqlite3OsDlOpen(PARENTVFS(pVfs), 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 tvfsDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
sqlite3OsDlError(PARENTVFS(pVfs), nByte, zErrMsg);
}
/*
** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
*/
static void (*tvfsDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
return sqlite3OsDlSym(PARENTVFS(pVfs), p, zSym);
}
/*
** Close the dynamic library handle pHandle.
*/
static void tvfsDlClose(sqlite3_vfs *pVfs, void *pHandle){
sqlite3OsDlClose(PARENTVFS(pVfs), pHandle);
}
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
/*
** Populate the buffer pointed to by zBufOut with nByte bytes of
** random data.
*/
static int tvfsRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
return sqlite3OsRandomness(PARENTVFS(pVfs), nByte, zBufOut);
}
/*
** Sleep for nMicro microseconds. Return the number of microseconds
** actually slept.
*/
static int tvfsSleep(sqlite3_vfs *pVfs, int nMicro){
return sqlite3OsSleep(PARENTVFS(pVfs), nMicro);
}
/*
** Return the current time as a Julian Day number in *pTimeOut.
*/
static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut);
}
static void tvfsGrowBuffer(TestvfsFile *pFd, int reqSize, int *pNewSize){
TestvfsBuffer *pBuffer = pFd->pShm;
if( reqSize>pBuffer->n ){
pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, reqSize);
memset(&pBuffer->a[pBuffer->n], 0x55, reqSize-pBuffer->n);
pBuffer->n = reqSize;
}
*pNewSize = pBuffer->n;
}
static void tvfsExecTcl(
Testvfs *p,
const char *zMethod,
Tcl_Obj *arg1,
Tcl_Obj *arg2,
Tcl_Obj *arg3
){
int rc; /* Return code from Tcl_EvalObj() */
int nArg; /* Elements in eval'd list */
p->apScript[p->nScript] = Tcl_NewStringObj(zMethod, -1);
p->apScript[p->nScript+1] = arg1;
p->apScript[p->nScript+2] = arg2;
p->apScript[p->nScript+3] = arg3;
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
Tcl_IncrRefCount(p->apScript[nArg]);
}
rc = Tcl_EvalObjv(p->interp, nArg, p->apScript, TCL_EVAL_GLOBAL);
if( rc!=TCL_OK ){
Tcl_BackgroundError(p->interp);
Tcl_ResetResult(p->interp);
}
for(nArg=p->nScript; p->apScript[nArg]; nArg++){
Tcl_DecrRefCount(p->apScript[nArg]);
p->apScript[nArg] = 0;
}
}
static int tvfsResultCode(Testvfs *p, int *pRc){
struct errcode {
int eCode;
const char *zCode;
} aCode[] = {
{ SQLITE_OK, "SQLITE_OK" },
{ SQLITE_ERROR, "SQLITE_ERROR" },
{ SQLITE_IOERR, "SQLITE_IOERR" },
{ SQLITE_LOCKED, "SQLITE_LOCKED" },
{ SQLITE_BUSY, "SQLITE_BUSY" },
};
const char *z;
int i;
z = Tcl_GetStringResult(p->interp);
for(i=0; i<ArraySize(aCode); i++){
if( 0==strcmp(z, aCode[i].zCode) ){
*pRc = aCode[i].eCode;
return 1;
}
}
return 0;
}
static int tvfsShmOpen(
sqlite3_file *pFileDes
){
Testvfs *p;
int rc = SQLITE_OK; /* Return code */
Tcl_Obj *pId = 0; /* Id for this connection */
TestvfsBuffer *pBuffer; /* Buffer to open connection to */
TestvfsFile *pFd; /* The testvfs file structure */
pFd = (TestvfsFile*)pFileDes;
p = (Testvfs *)pFd->pVfs->pAppData;
assert( pFd->pShmId==0 && pFd->pShm==0 );
/* Evaluate the Tcl script:
**
** SCRIPT xShmOpen FILENAME
**
** If the script returns an SQLite error code other than SQLITE_OK, an
** error is returned to the caller. If it returns SQLITE_OK, the new
** connection is named "anon". Otherwise, the value returned by the
** script is used as the connection name.
*/
tvfsExecTcl(p, "xShmOpen", Tcl_NewStringObj(pFd->zFilename, -1), 0, 0);
if( tvfsResultCode(p, &rc) ){
if( rc!=SQLITE_OK ) return rc;
pId = Tcl_NewStringObj("anon", -1);
}else{
pId = Tcl_GetObjResult(p->interp);
}
Tcl_IncrRefCount(pId);
pFd->pShmId = pId;
/* Search for a TestvfsBuffer. Create a new one if required. */
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
if( 0==strcmp(pFd->zFilename, pBuffer->zFile) ) break;
}
if( !pBuffer ){
int nByte = sizeof(TestvfsBuffer) + strlen(pFd->zFilename) + 1;
pBuffer = (TestvfsBuffer *)ckalloc(nByte);
memset(pBuffer, 0, nByte);
pBuffer->zFile = (char *)&pBuffer[1];
strcpy(pBuffer->zFile, pFd->zFilename);
pBuffer->pNext = p->pBuffer;
p->pBuffer = pBuffer;
}
/* Connect the TestvfsBuffer to the new TestvfsShm handle and return. */
pBuffer->nRef++;
pFd->pShm = pBuffer;
return SQLITE_OK;
}
static int tvfsShmSize(
sqlite3_file *pFile,
int reqSize,
int *pNewSize
){
int rc = SQLITE_OK;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmSize",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
if( rc==SQLITE_OK ){
tvfsGrowBuffer(pFd, reqSize, pNewSize);
}
return rc;
}
static int tvfsShmGet(
sqlite3_file *pFile,
int reqMapSize,
int *pMapSize,
void **pp
){
int rc = SQLITE_OK;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmGet",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
if( rc==SQLITE_OK ){
tvfsGrowBuffer(pFd, reqMapSize, pMapSize);
*pp = pFd->pShm->a;
}
return rc;
}
static int tvfsShmRelease(sqlite3_file *pFile){
int rc = SQLITE_OK;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
tvfsExecTcl(p, "xShmRelease",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
return rc;
}
static int tvfsShmLock(
sqlite3_file *pFile,
int desiredLock,
int *gotLock
){
int rc = SQLITE_OK;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
char *zLock = "";
switch( desiredLock ){
case SQLITE_SHM_READ: zLock = "READ"; break;
case SQLITE_SHM_WRITE: zLock = "WRITE"; break;
case SQLITE_SHM_CHECKPOINT: zLock = "CHECKPOINT"; break;
case SQLITE_SHM_RECOVER: zLock = "RECOVER"; break;
case SQLITE_SHM_PENDING: zLock = "PENDING"; break;
case SQLITE_SHM_UNLOCK: zLock = "UNLOCK"; break;
}
tvfsExecTcl(p, "xShmLock",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId,
Tcl_NewStringObj(zLock, -1)
);
tvfsResultCode(p, &rc);
if( rc==SQLITE_OK ){
*gotLock = desiredLock;
}
return rc;
}
static int tvfsShmClose(
sqlite3_file *pFile,
int deleteFlag
){
int rc = SQLITE_OK;
TestvfsFile *pFd = (TestvfsFile *)pFile;
Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);
TestvfsBuffer *pBuffer = pFd->pShm;
assert( pFd->pShmId && pFd->pShm );
#if 0
assert( (deleteFlag!=0)==(pBuffer->nRef==1) );
#endif
tvfsExecTcl(p, "xShmClose",
Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0
);
tvfsResultCode(p, &rc);
pBuffer->nRef--;
if( pBuffer->nRef==0 ){
TestvfsBuffer **pp;
for(pp=&p->pBuffer; *pp!=pBuffer; pp=&((*pp)->pNext));
*pp = (*pp)->pNext;
ckfree((char *)pBuffer->a);
ckfree((char *)pBuffer);
}
Tcl_DecrRefCount(pFd->pShmId);
pFd->pShmId = 0;
pFd->pShm = 0;
return rc;
}
static int testvfs_obj_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
Testvfs *p = (Testvfs *)cd;
static const char *CMD_strs[] = { "shm", "delete", 0 };
enum DB_enum { CMD_SHM, CMD_DELETE };
int i;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
return TCL_ERROR;
}
if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){
return TCL_ERROR;
}
Tcl_ResetResult(interp);
switch( (enum DB_enum)i ){
case CMD_SHM: {
TestvfsBuffer *pBuffer;
char *zName;
if( objc!=3 && objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "FILE ?VALUE?");
return TCL_ERROR;
}
zName = Tcl_GetString(objv[2]);
for(pBuffer=p->pBuffer; pBuffer; pBuffer=pBuffer->pNext){
if( 0==strcmp(pBuffer->zFile, zName) ) break;
}
if( !pBuffer ){
Tcl_AppendResult(interp, "no such file: ", zName, 0);
return TCL_ERROR;
}
if( objc==4 ){
int n;
u8 *a = Tcl_GetByteArrayFromObj(objv[3], &n);
pBuffer->a = (u8 *)ckrealloc((char *)pBuffer->a, n);
pBuffer->n = n;
memcpy(pBuffer->a, a, n);
}
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBuffer->a, pBuffer->n));
break;
}
case CMD_DELETE: {
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
break;
}
}
return TCL_OK;
}
static void testvfs_obj_del(ClientData cd){
int i;
Testvfs *p = (Testvfs *)cd;
for(i=0; i<p->nScript; i++){
Tcl_DecrRefCount(p->apScript[i]);
}
sqlite3_vfs_unregister(p->pVfs);
ckfree((char *)p->pVfs);
ckfree((char *)p);
}
#define TESTVFS_MAX_ARGS 12
/*
** Usage: testvfs ?-noshm? VFSNAME SCRIPT
**
** This command creates two things when it is invoked: an SQLite VFS, and
** a Tcl command. Both are named VFSNAME. The VFS is installed. It is not
** installed as the default VFS.
**
** The VFS passes all file I/O calls through to the underlying VFS.
**
** Whenever one of the xShmSize, xShmGet or xShmRelease methods of the VFS
** are invoked, the SCRIPT is executed as follows:
**
** SCRIPT xShmSize FILENAME ID
** SCRIPT xShmGet FILENAME ID
** SCRIPT xShmRelease FILENAME ID
**
** The value returned by the invocation of SCRIPT above is interpreted as
** an SQLite error code and returned to SQLite. Either a symbolic
** "SQLITE_OK" or numeric "0" value may be returned.
**
** The contents of the shared-memory buffer associated with a given file
** may be read and set using the following command:
**
** VFSNAME shm FILENAME ?NEWVALUE?
**
** When the xShmLock method is invoked by SQLite, the following script is
** run:
**
** SCRIPT xShmLock FILENAME ID LOCK
**
** where LOCK is one of "UNLOCK", "READ", "READ_FULL", "WRITE", "PENDING",
** "CHECKPOINT" or "RECOVER". The script should return an SQLite error
** code.
*/
static int testvfs_cmd(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
static sqlite3_vfs tvfs_vfs = {
2, /* iVersion */
sizeof(TestvfsFile), /* szOsFile */
0, /* mxPathname */
0, /* pNext */
0, /* zName */
0, /* pAppData */
tvfsOpen, /* xOpen */
tvfsDelete, /* xDelete */
tvfsAccess, /* xAccess */
tvfsFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
tvfsDlOpen, /* xDlOpen */
tvfsDlError, /* xDlError */
tvfsDlSym, /* xDlSym */
tvfsDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
tvfsRandomness, /* xRandomness */
tvfsSleep, /* xSleep */
tvfsCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0,
0,
};
Testvfs *p; /* New object */
sqlite3_vfs *pVfs; /* New VFS */
char *zVfs;
Tcl_Obj *pScript;
int nScript; /* Number of elements in list pScript */
Tcl_Obj **apScript; /* Array of pScript elements */
int nByte; /* Bytes of space to allocate at p */
int i; /* Counter variable */
int isNoshm = 0; /* True if -noshm is passed */
if( objc<3 ) goto bad_args;
if( strcmp(Tcl_GetString(objv[1]), "-noshm")==0 ){
isNoshm = 1;
}
if( objc!=3+isNoshm ) goto bad_args;
zVfs = Tcl_GetString(objv[isNoshm+1]);
pScript = objv[isNoshm+2];
if( TCL_OK!=Tcl_ListObjGetElements(interp, pScript, &nScript, &apScript) ){
return TCL_ERROR;
}
nByte = sizeof(Testvfs)
+ (nScript+TESTVFS_MAX_ARGS)*sizeof(Tcl_Obj *)
+ strlen(zVfs)+1;
p = (Testvfs *)ckalloc(nByte);
memset(p, 0, nByte);
p->pParent = sqlite3_vfs_find(0);
p->interp = interp;
p->nScript = nScript;
p->apScript = (Tcl_Obj **)&p[1];
for(i=0; i<nScript; i++){
p->apScript[i] = apScript[i];
Tcl_IncrRefCount(p->apScript[i]);
}
p->zName = (char *)&p->apScript[nScript+TESTVFS_MAX_ARGS];
strcpy(p->zName, zVfs);
pVfs = (sqlite3_vfs *)ckalloc(sizeof(sqlite3_vfs));
memcpy(pVfs, &tvfs_vfs, sizeof(sqlite3_vfs));
pVfs->pAppData = (void *)p;
pVfs->zName = p->zName;
pVfs->mxPathname = p->pParent->mxPathname;
pVfs->szOsFile += p->pParent->szOsFile;
p->pVfs = pVfs;
p->isNoshm = isNoshm;
Tcl_CreateObjCommand(interp, zVfs, testvfs_obj_cmd, p, testvfs_obj_del);
sqlite3_vfs_register(pVfs, 0);
return TCL_OK;
bad_args:
Tcl_WrongNumArgs(interp, 1, objv, "?-noshm? VFSNAME SCRIPT");
return TCL_ERROR;
}
int Sqlitetestvfs_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
return TCL_OK;
}
#endif
+1
View File
@@ -826,6 +826,7 @@ static TriggerPrg *codeRowTrigger(
pSubParse->pToplevel = pTop;
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
pSubParse->nQueryLoop = pParse->nQueryLoop;
v = sqlite3GetVdbe(pSubParse);
if( v ){
+15 -4
View File
@@ -103,7 +103,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes;
int nRes; /* Bytes of reserved space at the end of each page */
int nDb; /* Number of attached databases */
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
@@ -117,7 +118,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
saved_xTrace = db->xTrace;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
db->xTrace = 0;
@@ -138,15 +139,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
** time to parse and run the PRAGMA to turn journalling off than it does
** to write the journal header file.
*/
nDb = db->nDb;
if( sqlite3TempInMemory(db) ){
zSql = "ATTACH ':memory:' AS vacuum_db;";
}else{
zSql = "ATTACH '' AS vacuum_db;";
}
rc = execSql(db, pzErrMsg, zSql);
if( db->nDb>nDb ){
pDb = &db->aDb[db->nDb-1];
assert( strcmp(pDb->zName,"vacuum_db")==0 );
}
if( rc!=SQLITE_OK ) goto end_of_vacuum;
pDb = &db->aDb[db->nDb-1];
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
/* The call to execSql() to attach the temp database has left the file
@@ -168,6 +172,12 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
}
#endif
/* Do not attempt to change the page size for a WAL database */
if( sqlite3PagerJournalMode(sqlite3BtreePager(pMain),
PAGER_JOURNALMODE_QUERY)==PAGER_JOURNALMODE_WAL ){
db->nextPagesize = 0;
}
if( sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain), nRes, 0)
|| (!isMemDb && sqlite3BtreeSetPageSize(pTemp, db->nextPagesize, nRes, 0))
|| NEVER(db->mallocFailed)
@@ -304,6 +314,7 @@ end_of_vacuum:
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
db->xTrace = saved_xTrace;
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
/* Currently there is an SQL level transaction open on the vacuum
** database. No locks are held on any other files (since the main file
+170 -42
View File
@@ -989,38 +989,23 @@ case OP_Blob: { /* out2-prerelease */
break;
}
/* Opcode: Variable P1 P2 P3 P4 *
/* Opcode: Variable P1 P2 * P4 *
**
** Transfer the values of bound parameters P1..P1+P3-1 into registers
** P2..P2+P3-1.
** Transfer the values of bound parameter P1 into register P2
**
** If the parameter is named, then its name appears in P4 and P3==1.
** The P4 value is used by sqlite3_bind_parameter_name().
*/
case OP_Variable: {
int p1; /* Variable to copy from */
int p2; /* Register to copy to */
int n; /* Number of values left to copy */
case OP_Variable: { /* out2-prerelease */
Mem *pVar; /* Value being transferred */
p1 = pOp->p1 - 1;
p2 = pOp->p2;
n = pOp->p3;
assert( p1>=0 && p1+n<=p->nVar );
assert( p2>=1 && p2+n-1<=p->nMem );
assert( pOp->p4.z==0 || pOp->p3==1 || pOp->p3==0 );
while( n-- > 0 ){
pVar = &p->aVar[p1++];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
pOut = &aMem[p2++];
sqlite3VdbeMemReleaseExternal(pOut);
pOut->flags = MEM_Null;
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
assert( pOp->p1>0 && pOp->p1<=p->nVar );
pVar = &p->aVar[pOp->p1 - 1];
if( sqlite3VdbeMemTooBig(pVar) ){
goto too_big;
}
sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static);
UPDATE_MAX_BLOBSIZE(pOut);
break;
}
@@ -1383,7 +1368,7 @@ case OP_Function: {
for(i=0; i<n; i++, pArg++){
apVal[i] = pArg;
sqlite3VdbeMemStoreType(pArg);
REGISTER_TRACE(pOp->p2, pArg);
REGISTER_TRACE(pOp->p2+i, pArg);
}
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
@@ -3068,10 +3053,10 @@ case OP_OpenWrite: {
**
** Open a new cursor P1 to a transient table.
** The cursor is always opened read/write even if
** the main database is read-only. The transient or virtual
** the main database is read-only. The ephemeral
** table is deleted automatically when the cursor is closed.
**
** P2 is the number of columns in the virtual table.
** P2 is the number of columns in the ephemeral table.
** The cursor points to a BTree table if P4==0 and to a BTree index
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
** that defines the format of keys in the index.
@@ -3082,6 +3067,14 @@ case OP_OpenWrite: {
** this opcode. Then this opcode was call OpenVirtual. But
** that created confusion with the whole virtual-table idea.
*/
/* Opcode: OpenAutoindex P1 P2 * P4 *
**
** This opcode works the same as OP_OpenEphemeral. It has a
** different name to distinguish its use. Tables created using
** by this opcode will be used for automatically created transient
** indices in joins.
*/
case OP_OpenAutoindex:
case OP_OpenEphemeral: {
VdbeCursor *pCx;
static const int openFlags =
@@ -4190,7 +4183,7 @@ case OP_Rewind: { /* jump */
break;
}
/* Opcode: Next P1 P2 * * *
/* Opcode: Next P1 P2 * * P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index. If there are no more key/value pairs then fall through
@@ -4199,9 +4192,12 @@ case OP_Rewind: { /* jump */
**
** The P1 cursor must be for a real table, not a pseudo-table.
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
** See also: Prev
*/
/* Opcode: Prev P1 P2 * * *
/* Opcode: Prev P1 P2 * * P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index. If there is no previous key/value pairs then fall through
@@ -4209,6 +4205,9 @@ case OP_Rewind: { /* jump */
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
case OP_Prev: /* jump */
case OP_Next: { /* jump */
@@ -4218,6 +4217,7 @@ case OP_Next: { /* jump */
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<=ArraySize(p->aCounter) );
pC = p->apCsr[pOp->p1];
if( pC==0 ){
break; /* See ticket #2273 */
@@ -5171,6 +5171,146 @@ case OP_AggFinal: {
break;
}
#ifndef SQLITE_OMIT_WAL
/* Opcode: Checkpoint P1 * * * *
**
** Checkpoint database P1. This is a no-op if P1 is not currently in
** WAL mode.
*/
case OP_Checkpoint: {
rc = sqlite3Checkpoint(db, pOp->p1);
break;
};
#endif
/* Opcode: JournalMode P1 P2 P3 * P5
**
** Change the journal mode of database P1 to P3. P3 must be one of the
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
** modes (delete, truncate, persist, off and memory), this is a simple
** operation. No IO is required.
**
** If changing into or out of WAL mode the procedure is more complicated.
**
** Write a string containing the final journal-mode to register P2.
**
** If an attempt to change in to or out of WAL mode fails because another
** connection also has the same database open, then an SQLITE_BUSY error
** is raised if P5==0, or of P5!=0 the journal mode changed is skipped
** without signaling the error.
*/
case OP_JournalMode: { /* out2-prerelease */
Btree *pBt; /* Btree to change journal mode of */
Pager *pPager; /* Pager associated with pBt */
int eNew; /* New journal mode */
int eOld; /* The old journal mode */
const sqlite3_vfs *pVfs; /* The VFS of pPager */
const char *zFilename; /* Name of database file for pPager */
eNew = pOp->p3;
assert( eNew==PAGER_JOURNALMODE_DELETE
|| eNew==PAGER_JOURNALMODE_TRUNCATE
|| eNew==PAGER_JOURNALMODE_PERSIST
|| eNew==PAGER_JOURNALMODE_OFF
|| eNew==PAGER_JOURNALMODE_MEMORY
|| eNew==PAGER_JOURNALMODE_WAL
|| eNew==PAGER_JOURNALMODE_QUERY
);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
/* This opcode is used in two places: PRAGMA journal_mode and ATTACH.
** In PRAGMA journal_mode, the sqlite3VdbeUsesBtree() routine is called
** when the statment is prepared and so p->aMutex.nMutex>0. All mutexes
** are already acquired. But when used in ATTACH, sqlite3VdbeUsesBtree()
** is not called when the statement is prepared because it requires the
** iDb index of the database as a parameter, and the database has not
** yet been attached so that index is unavailable. We have to wait
** until runtime (now) to get the mutex on the newly attached database.
** No other mutexes are required by the ATTACH command so this is safe
** to do.
*/
assert( (p->btreeMask & (1<<pOp->p1))!=0 || p->aMutex.nMutex==0 );
if( p->aMutex.nMutex==0 ){
/* This occurs right after ATTACH. Get a mutex on the newly ATTACHed
** database. */
sqlite3VdbeUsesBtree(p, pOp->p1);
sqlite3VdbeMutexArrayEnter(p);
}
pBt = db->aDb[pOp->p1].pBt;
pPager = sqlite3BtreePager(pBt);
#ifndef SQLITE_OMIT_WAL
zFilename = sqlite3PagerFilename(pPager);
pVfs = sqlite3PagerVfs(pPager);
/* Do not allow a transition to journal_mode=WAL for a database
** in temporary storage or if the VFS does not support xShmOpen.
*/
if( eNew==PAGER_JOURNALMODE_WAL
&& (zFilename[0]==0 /* Temp file */
|| !sqlite3PagerWalSupported(pPager)) /* No xShmOpen support */
){
eNew = PAGER_JOURNALMODE_QUERY;
}
if( eNew!=PAGER_JOURNALMODE_QUERY ){
eOld = sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_QUERY);
if( (eNew!=eOld)
&& (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL)
){
if( !db->autoCommit || db->activeVdbeCnt>1 ){
rc = SQLITE_ERROR;
sqlite3SetString(&p->zErrMsg, db,
"cannot change %s wal mode from within a transaction",
(eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
);
break;
}else{
if( eOld==PAGER_JOURNALMODE_WAL ){
/* If leaving WAL mode, close the log file. If successful, the call
** to PagerCloseWal() checkpoints and deletes the write-ahead-log
** file. An EXCLUSIVE lock may still be held on the database file
** after a successful return.
*/
rc = sqlite3PagerCloseWal(pPager);
if( rc==SQLITE_OK ){
sqlite3PagerJournalMode(pPager, eNew);
}else if( rc==SQLITE_BUSY && pOp->p5==0 ){
goto abort_due_to_error;
}
}else{
sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
rc = SQLITE_OK;
}
/* Open a transaction on the database file. Regardless of the journal
** mode, this transaction always uses a rollback journal.
*/
assert( sqlite3BtreeIsInTrans(pBt)==0 );
if( rc==SQLITE_OK ){
rc = sqlite3BtreeSetVersion(pBt,
(eNew==PAGER_JOURNALMODE_WAL ? 2 : 1));
if( rc==SQLITE_BUSY && pOp->p5==0 ) goto abort_due_to_error;
}else if( rc==SQLITE_BUSY ){
eNew = PAGER_JOURNALMODE_QUERY;
rc = SQLITE_OK;
}
}
}
}
#endif /* ifndef SQLITE_OMIT_WAL */
eNew = sqlite3PagerJournalMode(pPager, eNew);
pOut = &aMem[pOp->p2];
pOut->flags = MEM_Str|MEM_Static|MEM_Term;
pOut->z = (char *)sqlite3JournalModename(eNew);
pOut->n = sqlite3Strlen30(pOut->z);
pOut->enc = SQLITE_UTF8;
sqlite3VdbeChangeEncoding(pOut, encoding);
break;
};
#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* Opcode: Vacuum * * * * *
@@ -5616,19 +5756,7 @@ case OP_VUpdate: {
** Write the current number of pages in database P1 to memory cell P2.
*/
case OP_Pagecount: { /* out2-prerelease */
int p1;
int nPage;
Pager *pPager;
p1 = pOp->p1;
pPager = sqlite3BtreePager(db->aDb[p1].pBt);
rc = sqlite3PagerPagecount(pPager, &nPage);
/* OP_Pagecount is always called from within a read transaction. The
** page count has already been successfully read and cached. So the
** sqlite3PagerPagecount() call above cannot fail. */
if( ALWAYS(rc==SQLITE_OK) ){
pOut->u.i = nPage;
}
pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
break;
}
#endif
+1 -1
View File
@@ -311,7 +311,7 @@ struct Vdbe {
int btreeMask; /* Bitmask of db->aDb[] entries referenced */
i64 startTime; /* Time when query started - used for profiling */
BtreeMutexArray aMutex; /* An array of Btree used here and needing locks */
int aCounter[2]; /* Counters used by sqlite3_stmt_status() */
int aCounter[3]; /* Counters used by sqlite3_stmt_status() */
char *zSql; /* Text of the SQL statement that generated this */
void *pFree; /* Free this when deleting the vdbe */
i64 nFkConstraint; /* Number of imm. FK constraints this VM */
+39 -13
View File
@@ -306,6 +306,27 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
pCtx->s.db->mallocFailed = 1;
}
/*
** This function is called after a transaction has been committed. It
** invokes callbacks registered with sqlite3_wal_hook() as required.
*/
static int doWalCallbacks(sqlite3 *db){
int rc = SQLITE_OK;
#ifndef SQLITE_OMIT_WAL
int i;
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
int nEntry = sqlite3PagerWalCallback(sqlite3BtreePager(pBt));
if( db->xWalCallback && nEntry>0 && rc==SQLITE_OK ){
rc = db->xWalCallback(db->pWalArg, db, db->aDb[i].zName, nEntry);
}
}
}
#endif
return rc;
}
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
@@ -321,9 +342,12 @@ static int sqlite3Step(Vdbe *p){
assert(p);
if( p->magic!=VDBE_MAGIC_RUN ){
sqlite3_log(SQLITE_MISUSE,
"attempt to step a halted statement: [%s]", p->zSql);
return SQLITE_MISUSE_BKPT;
/* We used to require that sqlite3_reset() be called before retrying
** sqlite3_step() after any error. But after 3.6.23, we changed this
** so that sqlite3_reset() would be called automatically instead of
** throwing the error.
*/
sqlite3_reset((sqlite3_stmt*)p);
}
/* Check that malloc() has not failed. If it has, return early. */
@@ -351,9 +375,7 @@ static int sqlite3Step(Vdbe *p){
#ifndef SQLITE_OMIT_TRACE
if( db->xProfile && !db->init.busy ){
double rNow;
sqlite3OsCurrentTime(db->pVfs, &rNow);
p->startTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}
#endif
@@ -374,16 +396,20 @@ static int sqlite3Step(Vdbe *p){
/* Invoke the profile callback if there is one
*/
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy && p->zSql ){
double rNow;
u64 elapseTime;
sqlite3OsCurrentTime(db->pVfs, &rNow);
elapseTime = (u64)((rNow - (int)rNow)*3600.0*24.0*1000000000.0);
elapseTime -= p->startTime;
db->xProfile(db->pProfileArg, p->zSql, elapseTime);
sqlite3_int64 iNow;
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
db->xProfile(db->pProfileArg, p->zSql, iNow - p->startTime);
}
#endif
if( rc==SQLITE_DONE ){
assert( p->rc==SQLITE_OK );
p->rc = doWalCallbacks(db);
if( p->rc!=SQLITE_OK ){
rc = SQLITE_ERROR;
}
}
db->errCode = rc;
if( SQLITE_NOMEM==sqlite3ApiExit(p->db, p->rc) ){
p->rc = SQLITE_NOMEM;
+7 -1
View File
@@ -743,7 +743,7 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
u8 *aSortOrder;
memcpy(pKeyInfo, zP4, nByte);
memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
if( aSortOrder ){
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
@@ -950,6 +950,11 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
/*
** Declare to the Vdbe that the BTree object at db->aDb[i] is used.
**
** The prepared statement has to know in advance which Btree objects
** will be used so that it can acquire mutexes on them all in sorted
** order (via sqlite3VdbeMutexArrayEnter(). Mutexes are acquired
** in order (and released in reverse order) to avoid deadlocks.
*/
void sqlite3VdbeUsesBtree(Vdbe *p, int i){
int mask;
@@ -1449,6 +1454,7 @@ void sqlite3VdbeMakeReady(
p->cacheCtr = 1;
p->minWriteFileFormat = 255;
p->iStatement = 0;
p->nFkConstraint = 0;
#ifdef VDBE_PROFILE
{
int i;
+1
View File
@@ -657,6 +657,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
}else{
pParse->declareVtab = 1;
pParse->db = db;
pParse->nQueryLoop = 1;
if( SQLITE_OK==sqlite3RunParser(pParse, zCreateTable, &zErr)
&& pParse->pNewTable
+1544
View File
File diff suppressed because it is too large Load Diff
+104
View File
@@ -0,0 +1,104 @@
/*
** 2010 February 1
**
** 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 header file defines the interface to the write-ahead logging
** system. Refer to the comments below and the header comment attached to
** the implementation of each function in log.c for further details.
*/
#ifndef _WAL_H_
#define _WAL_H_
#include "sqliteInt.h"
#ifdef SQLITE_OMIT_WAL
# define sqlite3WalOpen(x,y,z) 0
# define sqlite3WalClose(w,x,y,z) 0
# define sqlite3WalOpenSnapshot(y,z) 0
# define sqlite3WalCloseSnapshot(z)
# define sqlite3WalRead(v,w,x,y,z) 0
# define sqlite3WalDbsize(y,z)
# define sqlite3WalWriteLock(y,z) 0
# define sqlite3WalUndo(x,y,z) 0
# define sqlite3WalSavepoint(z) 0
# define sqlite3WalSavepointUndo(y,z) 0
# define sqlite3WalFrames(u,v,w,x,y,z) 0
# define sqlite3WalCheckpoint(u,v,w,x,y,z) 0
# define sqlite3WalCallback(z) 0
#else
/* Connection to a write-ahead log (WAL) file.
** There is one object of this type for each pager.
*/
typedef struct Wal Wal;
/* Open and close a connection to a write-ahead log. */
int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, Wal**);
int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *);
/* Used by readers to open (lock) and close (unlock) a snapshot. A
** snapshot is like a read-transaction. It is the state of the database
** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and
** preserves the current state even if the other threads or processes
** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the
** transaction and releases the lock.
*/
int sqlite3WalOpenSnapshot(Wal *pWal, int *);
void sqlite3WalCloseSnapshot(Wal *pWal);
/* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut);
/* Return the size of the database as it existed at the beginning
** of the snapshot */
void sqlite3WalDbsize(Wal *pWal, Pgno *pPgno);
/* Obtain or release the WRITER lock. */
int sqlite3WalWriteLock(Wal *pWal, int op);
/* Undo any frames written (but not committed) to the log */
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx);
/* Return an integer that records the current (uncommitted) write
** position in the WAL */
u32 sqlite3WalSavepoint(Wal *pWal);
/* Move the write position of the WAL back to iFrame. Called in
** response to a ROLLBACK TO command. */
int sqlite3WalSavepointUndo(Wal *pWal, u32 iFrame);
/* Write a frame or frames to the log. */
int sqlite3WalFrames(Wal *pWal, int, PgHdr *, Pgno, int, int);
/* Copy pages from the log to the database file */
int sqlite3WalCheckpoint(
Wal *pWal, /* Write-ahead log connection */
int sync_flags, /* Flags to sync db file with (or 0) */
int nBuf, /* Size of buffer nBuf */
u8 *zBuf, /* Temporary buffer to use */
int (*xBusyHandler)(void *), /* Pointer to busy-handler function */
void *pBusyHandlerArg /* Argument to pass to xBusyHandler */
);
/* Return the value to pass to a sqlite3_wal_hook callback, the
** number of frames in the WAL at the point of the last commit since
** sqlite3WalCallback() was called. If no commits have occurred since
** the last call, then return 0.
*/
int sqlite3WalCallback(Wal *pWal);
/* Tell the wal layer that an EXCLUSIVE lock has been obtained (or released)
** by the pager layer on the database file.
*/
int sqlite3WalExclusiveMode(Wal *pWal, int op);
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* _WAL_H_ */
+413 -43
View File
@@ -235,6 +235,7 @@ struct WhereCost {
#define WHERE_COLUMN_IN 0x00040000 /* x IN (...) */
#define WHERE_COLUMN_NULL 0x00080000 /* x IS NULL */
#define WHERE_INDEXED 0x000f0000 /* Anything that uses an index */
#define WHERE_NOT_FULLSCAN 0x000f3000 /* Does not do a full table scan */
#define WHERE_IN_ABLE 0x000f1000 /* Able to support an IN operator */
#define WHERE_TOP_LIMIT 0x00100000 /* x<EXPR or x<=EXPR constraint */
#define WHERE_BTM_LIMIT 0x00200000 /* x>EXPR or x>=EXPR constraint */
@@ -244,6 +245,7 @@ struct WhereCost {
#define WHERE_UNIQUE 0x04000000 /* Selects no more than one row */
#define WHERE_VIRTUALTABLE 0x08000000 /* Use virtual-table processing */
#define WHERE_MULTI_OR 0x10000000 /* OR using multiple indices */
#define WHERE_TEMP_INDEX 0x20000000 /* Uses an ephemeral index */
/*
** Initialize a preallocated WhereClause structure.
@@ -1573,6 +1575,11 @@ static void bestOrClauseIndex(
WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm]; /* End of pWC->a[] */
WhereTerm *pTerm; /* A single term of the WHERE clause */
/* No OR-clause optimization allowed if the NOT INDEXED clause is used */
if( pSrc->notIndexed ){
return;
}
/* Search the WHERE clause terms for a usable WO_OR term. */
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( pTerm->eOperator==WO_OR
@@ -1615,8 +1622,9 @@ static void bestOrClauseIndex(
/* If there is an ORDER BY clause, increase the scan cost to account
** for the cost of the sort. */
if( pOrderBy!=0 ){
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
rTotal, rTotal+nRow*estLog(nRow)));
rTotal += nRow*estLog(nRow);
WHERETRACE(("... sorting increases OR cost to %.9g\n", rTotal));
}
/* If the cost of scanning using this OR term for optimization is
@@ -1635,6 +1643,247 @@ static void bestOrClauseIndex(
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Return TRUE if the WHERE clause term pTerm is of a form where it
** could be used with an index to access pSrc, assuming an appropriate
** index existed.
*/
static int termCanDriveIndex(
WhereTerm *pTerm, /* WHERE clause term to check */
struct SrcList_item *pSrc, /* Table we are trying to access */
Bitmask notReady /* Tables in outer loops of the join */
){
char aff;
if( pTerm->leftCursor!=pSrc->iCursor ) return 0;
if( pTerm->eOperator!=WO_EQ ) return 0;
if( (pTerm->prereqRight & notReady)!=0 ) return 0;
aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity;
if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0;
return 1;
}
#endif
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** If the query plan for pSrc specified in pCost is a full table scan
** and indexing is allows (if there is no NOT INDEXED clause) and it
** possible to construct a transient index that would perform better
** than a full table scan even when the cost of constructing the index
** is taken into account, then alter the query plan to use the
** transient index.
*/
static void bestAutomaticIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to search */
Bitmask notReady, /* Mask of cursors that are not available */
WhereCost *pCost /* Lowest cost query plan */
){
double nTableRow; /* Rows in the input table */
double logN; /* log(nTableRow) */
double costTempIdx; /* per-query cost of the transient index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
WhereTerm *pWCEnd; /* End of pWC->a[] */
Table *pTable; /* Table tht might be indexed */
if( (pParse->db->flags & SQLITE_AutoIndex)==0 ){
/* Automatic indices are disabled at run-time */
return;
}
if( (pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)!=0 ){
/* We already have some kind of index in use for this query. */
return;
}
if( pSrc->notIndexed ){
/* The NOT INDEXED clause appears in the SQL. */
return;
}
assert( pParse->nQueryLoop >= (double)1 );
pTable = pSrc->pTab;
nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000;
logN = estLog(nTableRow);
costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1);
if( costTempIdx>=pCost->rCost ){
/* The cost of creating the transient table would be greater than
** doing the full table scan */
return;
}
/* Search for any equality comparison term */
pWCEnd = &pWC->a[pWC->nTerm];
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
WHERETRACE(("auto-index reduces cost from %.2f to %.2f\n",
pCost->rCost, costTempIdx));
pCost->rCost = costTempIdx;
pCost->nRow = logN + 1;
pCost->plan.wsFlags = WHERE_TEMP_INDEX;
pCost->used = pTerm->prereqRight;
break;
}
}
}
#else
# define bestAutomaticIndex(A,B,C,D,E) /* no-op */
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/*
** Generate code to construct the Index object for an automatic index
** and to set up the WhereLevel object pLevel so that the code generator
** makes use of the automatic index.
*/
static void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
WhereClause *pWC, /* The WHERE clause */
struct SrcList_item *pSrc, /* The FROM clause term to get the next index */
Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
int nColumn; /* Number of columns in the constructed index */
WhereTerm *pTerm; /* A single term of the WHERE clause */
WhereTerm *pWCEnd; /* End of pWC->a[] */
int nByte; /* Byte of memory needed for pIdx */
Index *pIdx; /* Object describing the transient index */
Vdbe *v; /* Prepared statement under construction */
int regIsInit; /* Register set by initialization */
int addrInit; /* Address of the initialization bypass jump */
Table *pTable; /* The table being indexed */
KeyInfo *pKeyinfo; /* Key information for the index */
int addrTop; /* Top of the index fill loop */
int regRecord; /* Register holding an index record */
int n; /* Column counter */
int i; /* Loop counter */
int mxBitCol; /* Maximum column in pSrc->colUsed */
CollSeq *pColl; /* Collating sequence to on a column */
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
/* Generate code to skip over the creation and initialization of the
** transient index on 2nd and subsequent iterations of the loop. */
v = pParse->pVdbe;
assert( v!=0 );
regIsInit = ++pParse->nMem;
addrInit = sqlite3VdbeAddOp1(v, OP_If, regIsInit);
sqlite3VdbeAddOp2(v, OP_Integer, 1, regIsInit);
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nColumn = 0;
pTable = pSrc->pTab;
pWCEnd = &pWC->a[pWC->nTerm];
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
testcase( iCol==BMS );
testcase( iCol==BMS-1 );
if( (idxCols & cMask)==0 ){
nColumn++;
idxCols |= cMask;
}
}
}
assert( nColumn>0 );
pLevel->plan.nEq = nColumn;
/* Count the number of additional columns needed to create a
** covering index. A "covering index" is an index that contains all
** columns that are needed by the query. With a covering index, the
** original table never needs to be accessed. Automatic indices must
** be a covering index because the index will not be updated if the
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
extraCols = pSrc->colUsed & (~idxCols | (((Bitmask)1)<<(BMS-1)));
mxBitCol = (pTable->nCol >= BMS-1) ? BMS-1 : pTable->nCol;
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
for(i=0; i<mxBitCol; i++){
if( extraCols & (((Bitmask)1)<<i) ) nColumn++;
}
if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
nColumn += pTable->nCol - BMS + 1;
}
pLevel->plan.wsFlags |= WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WO_EQ;
/* Construct the Index object to describe this index */
nByte = sizeof(Index);
nByte += nColumn*sizeof(int); /* Index.aiColumn */
nByte += nColumn*sizeof(char*); /* Index.azColl */
nByte += nColumn; /* Index.aSortOrder */
pIdx = sqlite3DbMallocZero(pParse->db, nByte);
if( pIdx==0 ) return;
pLevel->plan.u.pIdx = pIdx;
pIdx->azColl = (char**)&pIdx[1];
pIdx->aiColumn = (int*)&pIdx->azColl[nColumn];
pIdx->aSortOrder = (u8*)&pIdx->aiColumn[nColumn];
pIdx->zName = "auto-index";
pIdx->nColumn = nColumn;
pIdx->pTable = pTable;
n = 0;
idxCols = 0;
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
if( termCanDriveIndex(pTerm, pSrc, notReady) ){
int iCol = pTerm->u.leftColumn;
Bitmask cMask = iCol>=BMS ? ((Bitmask)1)<<(BMS-1) : ((Bitmask)1)<<iCol;
if( (idxCols & cMask)==0 ){
Expr *pX = pTerm->pExpr;
idxCols |= cMask;
pIdx->aiColumn[n] = pTerm->u.leftColumn;
pColl = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pX->pRight);
pIdx->azColl[n] = pColl->zName;
n++;
}
}
}
assert( n==pLevel->plan.nEq );
/* Add additional columns needed to make the automatic index into
** a covering index */
for(i=0; i<mxBitCol; i++){
if( extraCols & (((Bitmask)1)<<i) ){
pIdx->aiColumn[n] = i;
pIdx->azColl[n] = "BINARY";
n++;
}
}
if( pSrc->colUsed & (((Bitmask)1)<<(BMS-1)) ){
for(i=BMS-1; i<pTable->nCol; i++){
pIdx->aiColumn[n] = i;
pIdx->azColl[n] = "BINARY";
n++;
}
}
assert( n==nColumn );
/* Create the automatic index */
pKeyinfo = sqlite3IndexKeyinfo(pParse, pIdx);
assert( pLevel->iIdxCur>=0 );
sqlite3VdbeAddOp4(v, OP_OpenAutoindex, pLevel->iIdxCur, nColumn+1, 0,
(char*)pKeyinfo, P4_KEYINFO_HANDOFF);
VdbeComment((v, "for %s", pTable->zName));
/* Fill the automatic index with content */
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
regRecord = sqlite3GetTempReg(pParse);
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
sqlite3VdbeJumpHere(v, addrTop);
sqlite3ReleaseTempReg(pParse, regRecord);
/* Jump here when skipping the initialization */
sqlite3VdbeJumpHere(v, addrInit);
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Allocate and populate an sqlite3_index_info structure. It is the
@@ -1819,6 +2068,7 @@ static void bestVirtualIndex(
WhereTerm *pTerm;
int i, j;
int nOrderBy;
double rCost;
/* Make sure wsFlags is initialized to some sane value. Otherwise, if the
** malloc in allocateIndexInfo() fails and this function returns leaving
@@ -1905,6 +2155,15 @@ static void bestVirtualIndex(
}
}
/* If there is an ORDER BY clause, and the selected virtual table index
** does not satisfy it, increase the cost of the scan accordingly. This
** matches the processing for non-virtual tables in bestBtreeIndex().
*/
rCost = pIdxInfo->estimatedCost;
if( pOrderBy && pIdxInfo->orderByConsumed==0 ){
rCost += estLog(rCost)*rCost;
}
/* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
** inital value of lowestCost in this loop. If it is, then the
** (cost<lowestCost) test below will never be true.
@@ -1912,10 +2171,10 @@ static void bestVirtualIndex(
** Use "(double)2" instead of "2.0" in case OMIT_FLOATING_POINT
** is defined.
*/
if( (SQLITE_BIG_DBL/((double)2))<pIdxInfo->estimatedCost ){
if( (SQLITE_BIG_DBL/((double)2))<rCost ){
pCost->rCost = (SQLITE_BIG_DBL/((double)2));
}else{
pCost->rCost = pIdxInfo->estimatedCost;
pCost->rCost = rCost;
}
pCost->plan.u.pVtabIdx = pIdxInfo;
if( pIdxInfo->orderByConsumed ){
@@ -2316,14 +2575,14 @@ static void bestBtreeIndex(
** Set to true if there was at least one "x IN (SELECT ...)" term used
** in determining the value of nInMul.
**
** nBound:
** estBound:
** An estimate on the amount of the table that must be searched. A
** value of 100 means the entire table is searched. Range constraints
** might reduce this to a value less than 100 to indicate that only
** a fraction of the table needs searching. In the absence of
** sqlite_stat2 ANALYZE data, a single inequality reduces the search
** space to 1/3rd its original size. So an x>? constraint reduces
** nBound to 33. Two constraints (x>? AND x<?) reduce nBound to 11.
** estBound to 33. Two constraints (x>? AND x<?) reduce estBound to 11.
**
** bSort:
** Boolean. True if there is an ORDER BY clause that will require an
@@ -2345,13 +2604,14 @@ static void bestBtreeIndex(
int nEq;
int bInEst = 0;
int nInMul = 1;
int nBound = 100;
int estBound = 100;
int nBound = 0; /* Number of range constraints seen */
int bSort = 0;
int bLookup = 0;
WhereTerm *pTerm; /* A single term of the WHERE clause */
/* Determine the values of nEq and nInMul */
for(nEq=0; nEq<pProbe->nColumn; nEq++){
WhereTerm *pTerm; /* A single term of the WHERE clause */
int j = pProbe->aiColumn[nEq];
pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pIdx);
if( pTerm==0 ) break;
@@ -2371,18 +2631,20 @@ static void bestBtreeIndex(
used |= pTerm->prereqRight;
}
/* Determine the value of nBound. */
/* Determine the value of estBound. */
if( nEq<pProbe->nColumn ){
int j = pProbe->aiColumn[nEq];
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound);
if( pTop ){
nBound = 1;
wsFlags |= WHERE_TOP_LIMIT;
used |= pTop->prereqRight;
}
if( pBtm ){
nBound++;
wsFlags |= WHERE_BTM_LIMIT;
used |= pBtm->prereqRight;
}
@@ -2413,7 +2675,7 @@ static void bestBtreeIndex(
/* If currently calculating the cost of using an index (not the IPK
** index), determine if all required column data may be obtained without
** seeking to entries in the main table (i.e. if the index is a covering
** using the main table (i.e. if the index is a covering
** index for this query). If it is, set the WHERE_IDX_ONLY flag in
** wsFlags. Otherwise, set the bLookup variable to true. */
if( pIdx && wsFlags ){
@@ -2432,8 +2694,7 @@ static void bestBtreeIndex(
}
}
/**** Begin adding up the cost of using this index (Needs improvements)
**
/*
** Estimate the number of rows of output. For an IN operator,
** do not let the estimate exceed half the rows in the table.
*/
@@ -2452,8 +2713,8 @@ static void bestBtreeIndex(
/* Adjust the number of rows and the cost downward to reflect rows
** that are excluded by range constraints.
*/
nRow = (nRow * (double)nBound) / (double)100;
cost = (cost * (double)nBound) / (double)100;
nRow = (nRow * (double)estBound) / (double)100;
cost = (cost * (double)estBound) / (double)100;
/* Add in the estimated cost of sorting the result
*/
@@ -2470,17 +2731,75 @@ static void bestBtreeIndex(
}
/**** Cost of using this index has now been computed ****/
/* If there are additional constraints on this table that cannot
** be used with the current index, but which might lower the number
** of output rows, adjust the nRow value accordingly. This only
** matters if the current index is the least costly, so do not bother
** with this step if we already know this index will not be chosen.
** Also, never reduce the output row count below 2 using this step.
**
** Do not reduce the output row count if pSrc is the only table that
** is notReady; if notReady is a power of two. This will be the case
** when the main sqlite3WhereBegin() loop is scanning for a table with
** and "optimal" index, and on such a scan the output row count
** reduction is not valid because it does not update the "pCost->used"
** bitmap. The notReady bitmap will also be a power of two when we
** are scanning for the last table in a 64-way join. We are willing
** to bypass this optimization in that corner case.
*/
if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
int k; /* Loop counter */
int nSkipEq = nEq; /* Number of == constraints to skip */
int nSkipRange = nBound; /* Number of < constraints to skip */
Bitmask thisTab; /* Bitmap for pSrc */
thisTab = getMask(pWC->pMaskSet, iCur);
for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
if( nSkipEq ){
/* Ignore the first nEq equality matches since the index
** has already accounted for these */
nSkipEq--;
}else{
/* Assume each additional equality match reduces the result
** set size by a factor of 10 */
nRow /= 10;
}
}else if( pTerm->eOperator & (WO_LT|WO_LE|WO_GT|WO_GE) ){
if( nSkipRange ){
/* Ignore the first nBound range constraints since the index
** has already accounted for these */
nSkipRange--;
}else{
/* Assume each additional range constraint reduces the result
** set size by a factor of 3 */
nRow /= 3;
}
}else{
/* Any other expression lowers the output row count by half */
nRow /= 2;
}
}
if( nRow<2 ) nRow = 2;
}
WHERETRACE((
"tbl=%s idx=%s nEq=%d nInMul=%d nBound=%d bSort=%d bLookup=%d"
" wsFlags=%d (nRow=%.2f cost=%.2f)\n",
"%s(%s): nEq=%d nInMul=%d estBound=%d bSort=%d bLookup=%d wsFlags=0x%x\n"
" notReady=0x%llx nRow=%.2f cost=%.2f used=0x%llx\n",
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
nEq, nInMul, nBound, bSort, bLookup, wsFlags, nRow, cost
nEq, nInMul, estBound, bSort, bLookup, wsFlags,
notReady, nRow, cost, used
));
/* If this index is the best we have seen so far, then record this
** index and its cost in the pCost structure.
*/
if( (!pIdx || wsFlags) && cost<pCost->rCost ){
if( (!pIdx || wsFlags)
&& (cost<pCost->rCost || (cost<=pCost->rCost && nRow<pCost->nRow))
){
pCost->rCost = cost;
pCost->nRow = nRow;
pCost->used = used;
@@ -2515,10 +2834,12 @@ static void bestBtreeIndex(
);
WHERETRACE(("best index is: %s\n",
(pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" :
pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
));
bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
pCost->plan.wsFlags |= eqTermMask;
}
@@ -2576,7 +2897,7 @@ static void bestIndex(
*/
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm
&& ALWAYS((pTerm->wtFlags & TERM_CODED)==0)
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){
pTerm->wtFlags |= TERM_CODED;
@@ -2774,7 +3095,9 @@ static int codeAllEqualityTerms(
int k = pIdx->aiColumn[j];
pTerm = findTerm(pWC, iCur, k, notReady, pLevel->plan.wsFlags, pIdx);
if( NEVER(pTerm==0) ) break;
assert( (pTerm->wtFlags & TERM_CODED)==0 );
/* The following true for indices with redundant columns.
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
if( r1!=regBase+j ){
if( nReg==1 ){
@@ -2988,7 +3311,11 @@ static Bitmask codeOneLoopStart(
pLevel->op = bRev ? OP_Prev : OP_Next;
pLevel->p1 = iCur;
pLevel->p2 = start;
pLevel->p5 = (pStart==0 && pEnd==0) ?1:0;
if( pStart==0 && pEnd==0 ){
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}else{
assert( pLevel->p5==0 );
}
if( testOp!=OP_Noop ){
iRowidReg = iReleaseReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg);
@@ -3446,7 +3773,7 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
** Free a WhereInfo structure
*/
static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
if( pWInfo ){
if( ALWAYS(pWInfo) ){
int i;
for(i=0; i<pWInfo->nLevel; i++){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
@@ -3457,6 +3784,13 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
}
sqlite3DbFree(db, pInfo);
}
if( pWInfo->a[i].plan.wsFlags & WHERE_TEMP_INDEX ){
Index *pIdx = pWInfo->a[i].plan.u.pIdx;
if( pIdx ){
sqlite3DbFree(db, pIdx->zColAff);
sqlite3DbFree(db, pIdx);
}
}
}
whereClauseClear(pWInfo->pWC);
sqlite3DbFree(db, pWInfo);
@@ -3576,6 +3910,7 @@ WhereInfo *sqlite3WhereBegin(
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
*/
testcase( pTabList->nSrc==BMS );
if( pTabList->nSrc>BMS ){
sqlite3ErrorMsg(pParse, "at most %d tables in a join", BMS);
return 0;
@@ -3603,6 +3938,8 @@ WhereInfo *sqlite3WhereBegin(
sizeof(WhereMaskSet)
);
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
pWInfo = 0;
goto whereBeginError;
}
pWInfo->nLevel = nTabList;
@@ -3611,6 +3948,7 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->pWC = pWC = (WhereClause *)&((u8 *)pWInfo)[nByteWInfo];
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = (WhereMaskSet*)&pWC[1];
/* Split the WHERE clause into separate subexpressions where each
@@ -3712,20 +4050,25 @@ WhereInfo *sqlite3WhereBegin(
bestPlan.rCost = SQLITE_BIG_DBL;
/* Loop through the remaining entries in the FROM clause to find the
** next nested loop. The FROM clause entries may be iterated through
** next nested loop. The loop tests all FROM clause entries
** either once or twice.
**
** The first iteration, which is always performed, searches for the
** FROM clause entry that permits the lowest-cost, "optimal" scan. In
** The first test is always performed if there are two or more entries
** remaining and never performed if there is only one FROM clause entry
** to choose from. The first test looks for an "optimal" scan. In
** this context an optimal scan is one that uses the same strategy
** for the given FROM clause entry as would be selected if the entry
** were used as the innermost nested loop. In other words, a table
** is chosen such that the cost of running that table cannot be reduced
** by waiting for other tables to run first.
** by waiting for other tables to run first. This "optimal" test works
** by first assuming that the FROM clause is on the inner loop and finding
** its query plan, then checking to see if that query plan uses any
** other FROM clause terms that are notReady. If no notReady terms are
** used then the "optimal" query plan works.
**
** The second iteration is only performed if no optimal scan strategies
** were found by the first. This iteration is used to search for the
** lowest cost scan overall.
** The second loop iteration is only performed if no optimal scan
** strategies were found by the first loop. This 2nd iteration is used to
** search for the lowest cost scan overall.
**
** Previous versions of SQLite performed only the second iteration -
** the next outermost loop was always that with the lowest overall
@@ -3743,9 +4086,8 @@ WhereInfo *sqlite3WhereBegin(
** algorithm may choose to use t2 for the outer loop, which is a much
** costlier approach.
*/
for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
Bitmask mask = (isOptimal ? 0 : notReady);
assert( (nTabList-iFrom)>1 || isOptimal );
for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
Bitmask mask; /* Mask of tables not yet ready */
for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
WhereCost sCost; /* Cost information from best[Virtual]Index() */
@@ -3758,6 +4100,7 @@ WhereInfo *sqlite3WhereBegin(
if( j==iFrom ) iFrom++;
continue;
}
mask = (isOptimal ? m : notReady);
pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
assert( pTabItem->pTab );
@@ -3773,8 +4116,11 @@ WhereInfo *sqlite3WhereBegin(
assert( isOptimal || (sCost.used&notReady)==0 );
if( (sCost.used&notReady)==0
&& (j==iFrom || sCost.rCost<bestPlan.rCost)
&& (bestJ<0 || sCost.rCost<bestPlan.rCost
|| (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
){
WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
sCost.rCost, sCost.nRow));
bestPlan = sCost;
bestJ = j;
}
@@ -3790,13 +4136,16 @@ WhereInfo *sqlite3WhereBegin(
}
andFlags &= bestPlan.plan.wsFlags;
pLevel->plan = bestPlan.plan;
if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
testcase( bestPlan.plan.wsFlags & WHERE_INDEXED );
testcase( bestPlan.plan.wsFlags & WHERE_TEMP_INDEX );
if( bestPlan.plan.wsFlags & (WHERE_INDEXED|WHERE_TEMP_INDEX) ){
pLevel->iIdxCur = pParse->nTab++;
}else{
pLevel->iIdxCur = -1;
}
notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = (u8)bestJ;
if( bestPlan.nRow>=(double)1 ) pParse->nQueryLoop *= bestPlan.nRow;
/* Check that if the table scanned by this loop iteration had an
** INDEXED BY clause attached to it, that the named index is being
@@ -3843,6 +4192,7 @@ WhereInfo *sqlite3WhereBegin(
** searching those tables.
*/
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
notReady = ~(Bitmask)0;
for(i=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
Table *pTab; /* Table to open */
int iDb; /* Index of database containing table/index */
@@ -3855,7 +4205,9 @@ WhereInfo *sqlite3WhereBegin(
if( pItem->zAlias ){
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
}
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH AUTOMATIC INDEX", zMsg);
}else if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH INDEX %s",
zMsg, pLevel->plan.u.pIdx->zName);
}else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
@@ -3878,8 +4230,11 @@ WhereInfo *sqlite3WhereBegin(
#endif /* SQLITE_OMIT_EXPLAIN */
pTabItem = &pTabList->a[pLevel->iFrom];
pTab = pTabItem->pTab;
pLevel->iTabCur = pTabItem->iCursor;
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ){
/* Do nothing */
}else
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( (pLevel->plan.wsFlags & WHERE_VIRTUALTABLE)!=0 ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
@@ -3891,6 +4246,8 @@ WhereInfo *sqlite3WhereBegin(
&& (wctrlFlags & WHERE_OMIT_OPEN)==0 ){
int op = pWInfo->okOnePass ? OP_OpenWrite : OP_OpenRead;
sqlite3OpenTable(pParse, pTabItem->iCursor, iDb, pTab, op);
testcase( pTab->nCol==BMS-1 );
testcase( pTab->nCol==BMS );
if( !pWInfo->okOnePass && pTab->nCol<BMS ){
Bitmask b = pTabItem->colUsed;
int n = 0;
@@ -3902,7 +4259,11 @@ WhereInfo *sqlite3WhereBegin(
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
pLevel->iTabCur = pTabItem->iCursor;
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->plan.wsFlags & WHERE_TEMP_INDEX)!=0 ){
constructAutomaticIndex(pParse, pWC, pTabItem, notReady, pLevel);
}else
#endif
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
Index *pIx = pLevel->plan.u.pIdx;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
@@ -3914,8 +4275,10 @@ WhereInfo *sqlite3WhereBegin(
VdbeComment((v, "%s", pIx->zName));
}
sqlite3CodeVerifySchema(pParse, iDb);
notReady &= ~getMask(pWC->pMaskSet, pTabItem->iCursor);
}
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
if( db->mallocFailed ) goto whereBeginError;
/* Generate the code to do the search. Each iteration of the for
** loop below generates code for a single nested loop of the VM
@@ -3983,7 +4346,10 @@ WhereInfo *sqlite3WhereBegin(
/* Jump here if malloc fails */
whereBeginError:
whereInfoFree(db, pWInfo);
if( pWInfo ){
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
return 0;
}
@@ -4053,12 +4419,15 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
Table *pTab = pTabItem->pTab;
assert( pTab!=0 );
if( (pTab->tabFlags & TF_Ephemeral)!=0 || pTab->pSelect ) continue;
if( (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0 ){
if( !pWInfo->okOnePass && (pLevel->plan.wsFlags & WHERE_IDX_ONLY)==0 ){
if( (pTab->tabFlags & TF_Ephemeral)==0
&& pTab->pSelect==0
&& (pWInfo->wctrlFlags & WHERE_OMIT_CLOSE)==0
){
int ws = pLevel->plan.wsFlags;
if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor);
}
if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0 ){
if( (ws & WHERE_INDEXED)!=0 && (ws & WHERE_TEMP_INDEX)==0 ){
sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur);
}
}
@@ -4106,6 +4475,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Final cleanup
*/
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
return;
}
+23 -8
View File
@@ -173,6 +173,20 @@ ifcapable tempdb {
}
}
# Create bogus application-defined functions for functions used
# internally by ALTER TABLE, to ensure that ALTER TABLE falls back
# to the built-in functions.
#
proc failing_app_func {args} {error "bad function"}
do_test alter-1.7-prep {
db func substr failing_app_func
db func like failing_app_func
db func sqlite_rename_table failing_app_func
db func sqlite_rename_trigger failing_app_func
db func sqlite_rename_parent failing_app_func
catchsql {SELECT substr(name,1,3) FROM sqlite_master}
} {1 {bad function}}
# Make sure the ALTER TABLE statements work with the
# non-callback API
#
@@ -567,7 +581,8 @@ do_test alter-5.3 {
} {}
foreach tblname [execsql {
SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite%'
SELECT name FROM sqlite_master
WHERE type='table' AND name NOT GLOB 'sqlite*'
}] {
execsql "DROP TABLE \"$tblname\""
}
@@ -688,17 +703,17 @@ do_test alter-9.2 {
do_test alter-10.1 {
execsql "CREATE TABLE xyz(x UNIQUE)"
execsql "ALTER TABLE xyz RENAME TO xyz\u1234abc"
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'xyz%'}
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'xyz*'}
} [list xyz\u1234abc]
do_test alter-10.2 {
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_autoindex*'}
} [list sqlite_autoindex_xyz\u1234abc_1]
do_test alter-10.3 {
execsql "ALTER TABLE xyz\u1234abc RENAME TO xyzabc"
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'xyz%'}
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'xyz*'}
} [list xyzabc]
do_test alter-10.4 {
execsql {SELECT name FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
execsql {SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_autoindex*'}
} [list sqlite_autoindex_xyzabc_1]
do_test alter-11.1 {
@@ -795,19 +810,19 @@ do_test alter-13.1 {
CREATE TABLE t3102b -- comment
(y);
CREATE INDEX t3102c ON t3102a(x);
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
}
} {t3102a t3102b t3102c}
do_test alter-13.2 {
execsql {
ALTER TABLE t3102a RENAME TO t3102a_rename;
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
}
} {t3102a_rename t3102b t3102c}
do_test alter-13.3 {
execsql {
ALTER TABLE t3102b RENAME TO t3102b_rename;
SELECT name FROM sqlite_master WHERE name LIKE 't3102%' ORDER BY 1;
SELECT name FROM sqlite_master WHERE name GLOB 't3102*' ORDER BY 1;
}
} {t3102a_rename t3102b_rename t3102c}
+15
View File
@@ -72,6 +72,21 @@ proc alter_table {tbl sql {file_format 2}} {
set_file_format 2
}
# Create bogus application-defined functions for functions used
# internally by ALTER TABLE, to ensure that ALTER TABLE falls back
# to the built-in functions.
#
proc failing_app_func {args} {error "bad function"}
do_test alter2-1.0 {
db func substr failing_app_func
db func like failing_app_func
db func sqlite_rename_table failing_app_func
db func sqlite_rename_trigger failing_app_func
db func sqlite_rename_parent failing_app_func
catchsql {SELECT substr('abcdefg',1,3)}
} {1 {bad function}}
#-----------------------------------------------------------------------
# Some basic tests to make sure short rows are handled.
#
+1
View File
@@ -94,6 +94,7 @@ do_test async4.1.14 {
do_test async4.1.15 {
sqlite3async_start
sqlite3async_wait
hexio_write test.db 28 00000000
execsql { pragma integrity_check } db2
} {{*** in database main ***
Page 5 is never used}}
+139
View File
@@ -0,0 +1,139 @@
# 2010 April 07
#
# 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 script is testing automatic index creation logic.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If the library is not compiled with automatic index support then
# skip all tests in this file.
#
ifcapable {!autoindex} {
finish_test
return
}
# With automatic index turned off, we do a full scan of the T2 table
do_test autoindex1-100 {
db eval {
CREATE TABLE t1(a,b);
INSERT INTO t1 VALUES(1,11);
INSERT INTO t1 VALUES(2,22);
INSERT INTO t1 SELECT a+2, b+22 FROM t1;
INSERT INTO t1 SELECT a+4, b+44 FROM t1;
CREATE TABLE t2(c,d);
INSERT INTO t2 SELECT a, 900+b FROM t1;
}
db eval {
PRAGMA automatic_index=OFF;
SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
}
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
do_test autoindex1-101 {
db status step
} {63}
do_test autoindex1-102 {
db status autoindex
} {0}
# With autoindex turned on, we build an index once and then use that index
# to find T2 values.
do_test autoindex1-110 {
db eval {
PRAGMA automatic_index=ON;
SELECT b, d FROM t1 JOIN t2 ON a=c ORDER BY b;
}
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
do_test autoindex1-111 {
db status step
} {7}
do_test autoindex1-112 {
db status autoindex
} {7}
# The same test as above, but this time the T2 query is a subquery rather
# than a join.
do_test autoindex1-200 {
db eval {
PRAGMA automatic_index=OFF;
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
}
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
do_test autoindex1-201 {
db status step
} {35}
do_test autoindex1-202 {
db status autoindex
} {0}
do_test autoindex1-210 {
db eval {
PRAGMA automatic_index=ON;
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
}
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
do_test autoindex1-211 {
db status step
} {7}
do_test autoindex1-212 {
db status autoindex
} {7}
# Modify the second table of the join while the join is in progress
#
do_test autoindex1-300 {
set r {}
db eval {SELECT b, d FROM t1 JOIN t2 ON (c=a)} {
lappend r $b $d
db eval {UPDATE t2 SET d=d+1}
}
set r
} {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988}
do_test autoindex1-310 {
db eval {SELECT d FROM t2 ORDER BY d}
} {919 930 941 952 963 974 985 996}
# The next test does a 10-way join on unindexed tables. Without
# automatic indices, the join will take a long time to complete.
# With automatic indices, it should only take about a second.
#
do_test autoindex1-400 {
db eval {
CREATE TABLE t4(a, b);
INSERT INTO t4 VALUES(1,2);
INSERT INTO t4 VALUES(2,3);
}
for {set n 2} {$n<4096} {set n [expr {$n+$n}]} {
db eval {INSERT INTO t4 SELECT a+$n, b+$n FROM t4}
}
db eval {
SELECT count(*) FROM t4;
}
} {4096}
do_test autoindex1-401 {
db eval {
SELECT count(*)
FROM t4 AS x1
JOIN t4 AS x2 ON x2.a=x1.b
JOIN t4 AS x3 ON x3.a=x2.b
JOIN t4 AS x4 ON x4.a=x3.b
JOIN t4 AS x5 ON x5.a=x4.b
JOIN t4 AS x6 ON x6.a=x5.b
JOIN t4 AS x7 ON x7.a=x6.b
JOIN t4 AS x8 ON x8.a=x7.b
JOIN t4 AS x9 ON x9.a=x8.b
JOIN t4 AS x10 ON x10.a=x9.b;
}
} {4087}
finish_test
+7 -2
View File
@@ -22,8 +22,9 @@ source $testdir/tester.tcl
# Create several tables to work with.
#
do_test avtrans-1.0 {
execsql {
PRAGMA auto_vacuum=ON;
execsql { PRAGMA auto_vacuum=ON }
wal_set_journal_mode
execsql {
CREATE TABLE one(a int PRIMARY KEY, b text);
INSERT INTO one VALUES(1,'one');
INSERT INTO one VALUES(2,'two');
@@ -48,6 +49,7 @@ do_test avtrans-1.10 {
execsql {SELECT b FROM two ORDER BY a} altdb
} {I V X}
integrity_check avtrans-1.11
wal_check_journal_mode avtrans-1.12
# Basic transactions
#
@@ -84,6 +86,7 @@ do_test avtrans-2.10 {
}
} {1 2 3 1 5 10}
integrity_check avtrans-2.11
wal_check_journal_mode avtrans-2.12
# Check the locking behavior
#
@@ -913,9 +916,11 @@ for {set i 2} {$i<=$limit} {incr i} {
} {1}
}
}
wal_check_journal_mode avtrans-9.$i-6.$cnt
}
set ::pager_old_format 0
}
integrity_check avtrans-10.1
wal_check_journal_mode avtrans-10.2
finish_test
+4
View File
@@ -38,6 +38,8 @@ source $testdir/tester.tcl
#
# backup-9.*: Test that passing a negative argument to backup_step() is
# interpreted as "copy the whole file".
#
# backup-10.*: Test writing the source database mid backup.
#
proc data_checksum {db file} { $db one "SELECT md5sum(a, b) FROM ${file}.t1" }
@@ -487,6 +489,7 @@ db2 close
# 3) Backing up memory-to-file.
#
set iTest 0
file delete -force bak.db-wal
foreach {writer file} {db test.db db3 test.db db :memory:} {
incr iTest
catch { file delete bak.db }
@@ -905,6 +908,7 @@ ifcapable memorymanage {
}
#-----------------------------------------------------------------------
# Test that if the database is written to via the same database handle being
# used as the source by a backup operation:
#
+3
View File
@@ -69,6 +69,7 @@ if {[catch {fake_big_file 4096 [pwd]/test.db} msg]} {
finish_test
return
}
hexio_write test.db 28 00000000
do_test bigfile-1.2 {
sqlite3 db test.db
@@ -108,6 +109,7 @@ if {[catch {fake_big_file 8192 [pwd]/test.db}]} {
finish_test
return
}
hexio_write test.db 28 00000000
do_test bigfile-1.5 {
sqlite3 db test.db
@@ -146,6 +148,7 @@ if {[catch {fake_big_file 16384 [pwd]/test.db}]} {
finish_test
return
}
hexio_write test.db 28 00000000
do_test bigfile-1.10 {
sqlite3 db test.db
+6 -2
View File
@@ -71,15 +71,19 @@ do_test capi2-1.6 {
do_test capi2-1.7 {
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
} {2 {} {name rowid text INTEGER}}
do_test capi2-1.8-misuse {
# This used to be SQLITE_MISUSE. But now we automatically reset prepared
# statements.
do_test capi2-1.8 {
sqlite3_step $VM
} {SQLITE_MISUSE}
} {SQLITE_ROW}
# Update: In v2, once SQLITE_MISUSE is returned the statement handle cannot
# be interrogated for more information. However in v3, since the column
# count, names and types are determined at compile time, these are still
# accessible after an SQLITE_MISUSE error.
do_test capi2-1.9 {
sqlite3_reset $VM
list [sqlite3_column_count $VM] [get_row_values $VM] [get_column_names $VM]
} {2 {} {name rowid text INTEGER}}
do_test capi2-1.10 {
+2 -1
View File
@@ -321,6 +321,7 @@ do_test collate4-1.2.25 {
#
do_test collate4-2.1.0 {
execsql {
PRAGMA automatic_index=OFF;
CREATE TABLE collate4t1(a COLLATE NOCASE);
CREATE TABLE collate4t2(b COLLATE TEXT);
@@ -426,7 +427,7 @@ do_test collate4-2.2.0 {
} {}
do_test collate4-2.2.1 {
count {
SELECT * FROM collate4t2 NATURAL JOIN collate4t1;
SELECT * FROM collate4t2 NOT INDEXED NATURAL JOIN collate4t1 NOT INDEXED;
}
} {0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1 63}
do_test collate4-2.2.1b {
+2
View File
@@ -334,6 +334,7 @@ ifcapable autovacuum {
seek $fd 0 end
puts -nonewline $fd [string repeat x $nAppend]
close $fd
hexio_write corrupt.db 28 00000000
} -test {
do_test corrupt2-6.4 {
catchsql {
@@ -522,6 +523,7 @@ ifcapable autovacuum {
file size corrupt.db
} $::sqlite_pending_byte
hexio_write corrupt.db [expr $::sqlite_pending_byte+1023] 00
hexio_write corrupt.db 28 00000000
} -test {
do_test corrupt2-13.2 {
file size corrupt.db
+3 -1
View File
@@ -37,9 +37,11 @@ integrity_check corruptA-1.2
db close
file copy -force test.db test.db-template
set unreadable_version 02
ifcapable wal { set unreadable_version 03 }
do_test corruptA-2.1 {
file copy -force test.db-template test.db
hexio_write test.db 19 02 ;# the read format number
hexio_write test.db 19 $unreadable_version ;# the read format number
sqlite3 db test.db
catchsql {SELECT * FROM t1}
} {1 {file is encrypted or is not a database}}
+1 -1
View File
@@ -154,7 +154,7 @@ do_test corruptB-2.1.1 {
do_test corruptB-2.1.2 {
sqlite3 db test.db
catchsql { SELECT * FROM t1 }
} {1 {database or disk is full}}
} {1 {database disk image is malformed}}
#---------------------------------------------------------------------------
+7
View File
@@ -21,6 +21,13 @@ catch {file delete -force test.db test.db-journal test.bu}
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Do not run the tests in this file if ENABLE_OVERSIZE_CELL_CHECK is on.
#
ifcapable oversize_cell_check {
finish_test
return
}
# Construct a compact, dense database for testing.
#
do_test corruptE-1.1 {
+45
View File
@@ -0,0 +1,45 @@
# 2010 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.
#
#***********************************************************************
#
# Tests for the sqlite3_db_status() function
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Make sure sqlite3_db_config() and sqlite3_db_status are working.
#
unset -nocomplain PAGESZ
unset -nocomplain BASESZ
do_test dbstatus-1.1 {
db close
sqlite3 db :memory:
db eval {
CREATE TABLE t1(x);
}
set sz1 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
db eval {
CREATE TABLE t2(y);
}
set sz2 [lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1]
set ::PAGESZ [expr {$sz2-$sz1}]
set ::BASESZ [expr {$sz1-$::PAGESZ}]
expr {$::PAGESZ>1024 && $::PAGESZ<1200}
} {1}
do_test dbstatus-1.2 {
db eval {
INSERT INTO t1 VALUES(zeroblob(9000));
}
lindex [sqlite3_db_status db SQLITE_DBSTATUS_CACHE_USED 0] 1
} [expr {$BASESZ + 10*$PAGESZ}]
finish_test
+1
View File
@@ -252,6 +252,7 @@ ddl_test 1.3.2.8 { DROP TABLE docs }
# Test the examples in section 3 (full-text index queries).
#
ddl_test 1.4.1.1 { CREATE VIRTUAL TABLE docs USING fts3(title, body) }
unset -nocomplain R
foreach {tn title body} {
2 "linux driver" "a device"
3 "driver" "linguistic trick"
+27 -1
View File
@@ -1410,7 +1410,7 @@ do_test fkey2-17.1.2 {
} {SQLITE_CONSTRAINT}
do_test fkey2-17.1.3 {
sqlite3_step $STMT
} {SQLITE_MISUSE}
} {SQLITE_CONSTRAINT}
do_test fkey2-17.1.4 {
sqlite3_finalize $STMT
} {SQLITE_CONSTRAINT}
@@ -1598,6 +1598,32 @@ ifcapable auth {
unset authargs
}
do_test fkey2-19.1 {
execsql {
CREATE TABLE main(id INTEGER PRIMARY KEY);
CREATE TABLE sub(id INT REFERENCES main(id));
INSERT INTO main VALUES(1);
INSERT INTO main VALUES(2);
INSERT INTO sub VALUES(2);
}
} {}
do_test fkey2-19.2 {
set S [sqlite3_prepare_v2 db "DELETE FROM main WHERE id = ?" -1 dummy]
sqlite3_bind_int $S 1 2
sqlite3_step $S
} {SQLITE_CONSTRAINT}
do_test fkey2-19.3 {
sqlite3_reset $S
} {SQLITE_CONSTRAINT}
do_test fkey2-19.4 {
sqlite3_bind_int $S 1 1
sqlite3_step $S
} {SQLITE_DONE}
do_test fkey2-19.4 {
sqlite3_finalize $S
} {SQLITE_OK}
#-------------------------------------------------------------------------
# The following block of tests, those prefixed with "fkey2-genfkey.", are
# the same tests that were used to test the ".genfkey" command provided
-152
View File
@@ -288,155 +288,3 @@ proc fts3_read {tbl where varname} {
##########################################################################
#-------------------------------------------------------------------------
# This proc is used to test a single SELECT statement. Parameter $name is
# passed a name for the test case (i.e. "fts3_malloc-1.4.1") and parameter
# $sql is passed the text of the SELECT statement. Parameter $result is
# set to the expected output if the SELECT statement is successfully
# executed using [db eval].
#
# Example:
#
# do_select_test testcase-1.1 "SELECT 1+1, 1+2" {1 2}
#
# If global variable DO_MALLOC_TEST is set to a non-zero value, or if
# it is not defined at all, then OOM testing is performed on the SELECT
# statement. Each OOM test case is said to pass if either (a) executing
# the SELECT statement succeeds and the results match those specified
# by parameter $result, or (b) TCL throws an "out of memory" error.
#
# If DO_MALLOC_TEST is defined and set to zero, then the SELECT statement
# is executed just once. In this case the test case passes if the results
# match the expected results passed via parameter $result.
#
proc do_select_test {name sql result} {
uplevel [list doPassiveTest 0 $name $sql [list 0 $result]]
}
proc do_restart_select_test {name sql result} {
uplevel [list doPassiveTest 1 $name $sql [list 0 $result]]
}
proc do_error_test {name sql error} {
uplevel [list doPassiveTest 0 $name $sql [list 1 $error]]
}
proc doPassiveTest {isRestart name sql catchres} {
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
switch $::DO_MALLOC_TEST {
0 { # No malloc failures.
do_test $name [list set {} [uplevel [list catchsql $sql]]] $catchres
return
}
1 { # Simulate transient failures.
set nRepeat 1
set zName "transient"
set nStartLimit 100000
set nBackup 1
}
2 { # Simulate persistent failures.
set nRepeat 1
set zName "persistent"
set nStartLimit 100000
set nBackup 1
}
3 { # Simulate transient failures with extra brute force.
set nRepeat 100000
set zName "ridiculous"
set nStartLimit 1
set nBackup 10
}
}
# The set of acceptable results from running [catchsql $sql].
#
set answers [list {1 {out of memory}} $catchres]
set str [join $answers " OR "]
set nFail 1
for {set iLimit $nStartLimit} {$nFail} {incr iLimit} {
for {set iFail 1} {$nFail && $iFail<=$iLimit} {incr iFail} {
for {set iTest 0} {$iTest<$nBackup && ($iFail-$iTest)>0} {incr iTest} {
if {$isRestart} { sqlite3 db test.db }
sqlite3_memdebug_fail [expr $iFail-$iTest] -repeat $nRepeat
set res [uplevel [list catchsql $sql]]
if {[lsearch -exact $answers $res]>=0} { set res $str }
set testname "$name.$zName.$iFail"
do_test "$name.$zName.$iLimit.$iFail" [list set {} $res] $str
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
}
}
}
}
#-------------------------------------------------------------------------
# Test a single write to the database. In this case a "write" is a
# DELETE, UPDATE or INSERT statement.
#
# If OOM testing is performed, there are several acceptable outcomes:
#
# 1) The write succeeds. No error is returned.
#
# 2) An "out of memory" exception is thrown and:
#
# a) The statement has no effect, OR
# b) The current transaction is rolled back, OR
# c) The statement succeeds. This can only happen if the connection
# is in auto-commit mode (after the statement is executed, so this
# includes COMMIT statements).
#
# If the write operation eventually succeeds, zero is returned. If a
# transaction is rolled back, non-zero is returned.
#
# Parameter $name is the name to use for the test case (or test cases).
# The second parameter, $tbl, should be the name of the database table
# being modified. Parameter $sql contains the SQL statement to test.
#
proc do_write_test {name tbl sql} {
if {![info exists ::DO_MALLOC_TEST]} { set ::DO_MALLOC_TEST 1 }
# Figure out an statement to get a checksum for table $tbl.
db eval "SELECT * FROM $tbl" V break
set cksumsql "SELECT md5sum([join [concat rowid $V(*)] ,]) FROM $tbl"
# Calculate the initial table checksum.
set cksum1 [db one $cksumsql]
if {$::DO_MALLOC_TEST } {
set answers [list {1 {out of memory}} {0 {}}]
if {$::DO_MALLOC_TEST==1} {
set modes {100000 transient}
} else {
set modes {1 persistent}
}
} else {
set answers [list {0 {}}]
set modes [list 0 nofail]
}
set str [join $answers " OR "]
foreach {nRepeat zName} $modes {
for {set iFail 1} 1 {incr iFail} {
if {$::DO_MALLOC_TEST} {sqlite3_memdebug_fail $iFail -repeat $nRepeat}
set res [uplevel [list catchsql $sql]]
set nFail [sqlite3_memdebug_fail -1 -benigncnt nBenign]
if {$nFail==0} {
do_test $name.$zName.$iFail [list set {} $res] {0 {}}
return
} else {
if {[lsearch $answers $res]>=0} {
set res $str
}
do_test $name.$zName.$iFail [list set {} $res] $str
set cksum2 [db one $cksumsql]
if {$cksum1 != $cksum2} return
}
}
}
}
+29
View File
@@ -20,6 +20,7 @@ source $testdir/tester.tcl
# If this build does not include FTS3, skip the tests in this file.
#
ifcapable !fts3 { finish_test ; return }
source $testdir/malloc_common.tcl
source $testdir/fts3_common.tcl
set DO_MALLOC_TEST 0
@@ -101,5 +102,33 @@ do_test fts3query-3.3 {
execsql { SELECT mit(matchinfo(foobar)) FROM foobar WHERE foobar MATCH 'the' }
} {{1 1 3 3 1}}
# The following tests check that ticket 775b39dd3c has been fixed.
#
proc eqp {sql} {
uplevel [list execsql "EXPLAIN QUERY PLAN $sql"]
}
do_test fts3query-4.1 {
execsql {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(number INTEGER PRIMARY KEY, date);
CREATE INDEX i1 ON t1(date);
CREATE VIRTUAL TABLE ft USING fts3(title);
CREATE TABLE bt(title);
}
} {}
do_test fts3query-4.2 {
eqp "SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date"
} {0 0 {TABLE t1 WITH INDEX i1 ORDER BY} 1 1 {TABLE ft VIRTUAL TABLE INDEX 1:}}
do_test fts3query-4.3 {
eqp "SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date"
} {0 1 {TABLE t1 WITH INDEX i1 ORDER BY} 1 0 {TABLE ft VIRTUAL TABLE INDEX 1:}}
do_test fts3query-4.4 {
eqp "SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date"
} {0 0 {TABLE t1 WITH INDEX i1 ORDER BY} 1 1 {TABLE bt USING PRIMARY KEY}}
do_test fts3query-4.5 {
eqp "SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date"
} {0 1 {TABLE t1 WITH INDEX i1 ORDER BY} 1 0 {TABLE bt USING PRIMARY KEY}}
finish_test
+1
View File
@@ -82,6 +82,7 @@ source $testdir/tester.tcl
#
ifcapable !fts3 { finish_test ; return }
source $testdir/fts3_common.tcl
source $testdir/malloc_common.tcl
set G(nVocab) 100
+27
View File
@@ -334,4 +334,31 @@ do_test hook-5.2.2 {
# End rollback-hook testing.
#----------------------------------------------------------------------------
#----------------------------------------------------------------------------
# Test that if a commit-hook returns non-zero (causing a rollback), the
# rollback-hook is invoked.
#
proc commit_hook {} {
lappend ::hooks COMMIT
return 1
}
proc rollback_hook {} {
lappend ::hooks ROLLBACK
}
do_test hook-6.1 {
set ::hooks [list]
db commit_hook commit_hook
db rollback_hook rollback_hook
catchsql {
BEGIN;
INSERT INTO t1 VALUES('two', 'II');
COMMIT;
}
execsql { SELECT * FROM t1 }
} {one I}
do_test hook-6.2 {
set ::hooks
} {COMMIT ROLLBACK}
unset ::hooks
finish_test
+4 -1
View File
@@ -17,6 +17,10 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {[db eval {SELECT sqlite_compileoption_used('THREADSAFE=0')}]} {
finish_test
return
}
db close
@@ -76,4 +80,3 @@ if {$MEMDEBUG} {
autoinstall_test_functions
finish_test
+13 -4
View File
@@ -200,10 +200,16 @@ do_test io-2.5.3 {
# journal file is not actually created until the 'COMMIT' statement
# is executed.
#
# Changed 2010-03-27: The size of the database is now stored in
# bytes 28..31 and so when a page is added to the database, page 1
# is immediately modified and the journal file immediately comes into
# existance. To fix this test, the BEGIN is changed into a a
# BEGIN IMMEDIATE and the INSERT is omitted.
#
do_test io-2.6.1 {
execsql {
BEGIN;
INSERT INTO abc VALUES(9, randstr(1000,1000));
BEGIN IMMEDIATE;
-- INSERT INTO abc VALUES(9, randstr(1000,1000));
}
file exists test.db-journal
} {0}
@@ -213,12 +219,15 @@ do_test io-2.6.2 {
# should fail with SQLITE_CANTOPEN and the transaction rolled back.
#
file mkdir test.db-journal
catchsql { COMMIT }
catchsql {
INSERT INTO abc VALUES(9, randstr(1000,1000));
COMMIT
}
} {1 {unable to open database file}}
do_test io-2.6.3 {
file delete -force test.db-journal
catchsql { COMMIT }
} {1 {cannot commit - no transaction is active}}
} {0 {}}
do_test io-2.6.4 {
execsql { SELECT * FROM abc }
} {1 2 3 4 5 6 7 8}

Some files were not shown because too many files have changed in this diff Show More