Compare commits

..

115 Commits

Author SHA1 Message Date
drh c5cd124900 Increase the number of bits available in Expr.flags. Other tweaks aimed at
making expression processing more robust.

FossilOrigin-Name: 579a512538528cf4bb4381ba393c5d9e7310086b
2013-09-12 16:50:49 +00:00
mistachkin a9cb5be49a For error log messages generated by the Win32 native allocator, make sure the correct format specifier is used for the value returned by GetLastError().
FossilOrigin-Name: 75a8a8c1b39725d36db627536d0c69401f8e0815
2013-09-12 02:09:05 +00:00
mistachkin 36ca5359dc Fix a couple more harmless compiler warnings.
FossilOrigin-Name: 59708674f66e06c9c31c1a24f2f1c51f0bf4fa3e
2013-09-12 01:47:57 +00:00
drh 4a1f4ff53b Remove two obsolete fields from the sqlite3 object.
FossilOrigin-Name: 117fa5fbc9bed1a7b982c8ddc21b7e228905ccb4
2013-09-12 01:33:53 +00:00
mistachkin 61b7060c4f Fix harmless compiler warning.
FossilOrigin-Name: 2b510614dc6d878bd49eb428f167014f7f2e2568
2013-09-12 00:54:59 +00:00
drh 89a75397e0 Add test cases to cover TPC-H Q8.
FossilOrigin-Name: eb5cef8351d12c0f8550dac96ee7a6e495975b5a
2013-09-11 14:57:11 +00:00
drh 1d2b3c1f8a Deterministically initialize the PRNG used as a tie-breaker in the ANALYZE
command, so that the analysis is always the same given the same database.
This simplifies testing.

FossilOrigin-Name: 48ed8b565b84c8fa7898c2f9817c01f7e9c9182e
2013-09-10 01:41:25 +00:00
drh 0259bc3da2 Make sure that the transitive constraint optimization does not cause
WHERE clause terms to be disabled prematurely.  We are unable to find a test
case that fails because of this, but it seems prudent to make this
preventative change nevertheless.

FossilOrigin-Name: d6e361d7fb8013d616af91ef2c10038c97d1be5f
2013-09-09 19:37:46 +00:00
drh d36e104112 Combine the FuncDef.iPrefEnc and FuncDef.flags fields into a single
new FuncDef.funcFlags field.

FossilOrigin-Name: 97b10e66e98e84755aa577f8da017bf1aea2056c
2013-09-06 13:10:12 +00:00
drh 0d31dc37ac Make sure the destination WhereLoop is left in a sane state when an
OOM fault occurs inside of whereLoopXfer().

FossilOrigin-Name: a99a53b81e29c9514b85318bea028d1667e5f760
2013-09-06 00:40:59 +00:00
dan 8ff2d9561a When preparing an UPDATE statement, avoid generating VDBE code for those foreign key related actions and constraint checks that may be seen to be unnecessary by considering the subset of table columns potentially modified by the UPDATE.
FossilOrigin-Name: e940b5de49baa1d6a4cf859fbbc0e0df86ac5dbf
2013-09-05 18:40:29 +00:00
drh 74dade2155 Rearrange the order of conditions in an "if" statement to facilitate testing.
FossilOrigin-Name: 8462fb43c275a70db59c4339650225deeadeef00
2013-09-04 18:14:53 +00:00
dan af0d8bcf4b Add tests to improve coverage when SQLITE_ENABLE_STAT3 is defined.
FossilOrigin-Name: f929e9b41f2f69b086be3dd48fe557adbba7ae5c
2013-09-04 16:38:42 +00:00
drh 55a1b30875 Fix a bug in the command-line shell for ".mode insert" on UTF16 databases
with BLOB values.

FossilOrigin-Name: d8fdc7821808e2bfa048144ee3015b745232dc30
2013-09-04 16:08:50 +00:00
drh 2b1a64a120 The sqlite3Stat4ProbeSetValue() routine should always return results using
the database encoding.

FossilOrigin-Name: eb21663271369c3862bc8fd800f76d568c8579fe
2013-09-04 15:15:10 +00:00
mistachkin c2cfb51525 Fix out-of-order variable declaration. Fix harmless compiler warning.
FossilOrigin-Name: 8df95bb0b3f72222cf262174247a467c234f9939
2013-09-04 04:04:08 +00:00
drh 30f07042df Conditionally exclude code from analyze.c that is not used by STAT3.
FossilOrigin-Name: a48948a170056dfb87541dd5eb2773094dec6f8a
2013-09-04 02:07:38 +00:00
drh fbc38de980 Harden the STAT4 logic in where.c against OOM faults.
FossilOrigin-Name: 91d2cfbc95c34c0040deb69106bb9f895abb94c0
2013-09-03 19:26:22 +00:00
dan b13af4c5dd Fix another problem in stat4 sample selection.
FossilOrigin-Name: d59f580904e6e7e90fc0a692a3dd4eeff5942479
2013-09-03 14:43:12 +00:00
drh 67a5ec7b54 Make sure the omit-noop-left-join optimization is not applied if columns
of the LEFT JOIN are used in the ORDER BY clause.  
Ticket [be84e357c035]

FossilOrigin-Name: 0303d6bc7112e6f810ae1bd75cafc5ffc51f5212
2013-09-03 14:03:47 +00:00
drh 05db3c7743 Simplify branch coverage testing by interchanging the order of two tests
in the whereLoopInsert() function.

FossilOrigin-Name: f7079b5365dd6cd8324a4fb23605e81476122ed6
2013-09-02 20:22:18 +00:00
dan b49d1047c6 Further stat4 related tests.
FossilOrigin-Name: 0a702c4b4c35fdbcb62e3ab88b9e57d7ea0052a8
2013-09-02 18:58:11 +00:00
dan 84f48296fa Add tests to check if ANALYZE is choosing common non-periodic samples for the stat4 table.
FossilOrigin-Name: 175842997af134138784bff6f8e93573deb5b36b
2013-09-02 11:52:11 +00:00
dan 575ab2f8f6 Fix a problem with using stat4 data to estimate the number of rows scanned by a range constraint on the second or subsequent column of any index where an affinity transformation must be applied to the constraint argument.
FossilOrigin-Name: c21f58d84859e479a6cc619671a0df48b2f9692e
2013-09-02 07:16:40 +00:00
drh 1df556e6f2 Cleanup of the windows VFS, including added support for Cygwin, fixes
for compiler warnings under unusual configurations, and improved diagnostic
error messages.

FossilOrigin-Name: c94933f13208f3f7d6d1b117ce6d2821100655a4
2013-08-31 18:36:14 +00:00
mistachkin 1a88b14e5d Revise the amalgamation tool to allow 'duplicate' include files to be retained manually while still preserving the existing line numbers.
FossilOrigin-Name: aa48284637b954d63bcf77e19b25e75c7ad1a6d3
2013-08-31 18:06:52 +00:00
dan 4a1aa3851a Fix a problem causing SQLite not to use stat4 or stat3 data to analyze constraints of the form "column = expr COLLATE collation" (those with an explicit COLLATE on the non-column side of the comparison operator).
FossilOrigin-Name: 1e86d81d46c9da6aaee0c6938ee40933f35e3d0d
2013-08-31 17:21:26 +00:00
mistachkin 28159a5ee9 Enhancements to the Win32 API definition macros.
FossilOrigin-Name: b1811baab6e35ecb1ba920a7ed3302997758d309
2013-08-31 17:01:56 +00:00
dan 3fa2a82b8b Reenable a test accidentally disabled when the stat4 branch was merged.
FossilOrigin-Name: d9fadc8fa6ef02d516678d57896d93e0a5f52cfe
2013-08-31 14:56:30 +00:00
mistachkin 2a43c28f06 Avoid commenting out #include statements when building the amalgamation source code file.
FossilOrigin-Name: 2fca6d784b000fd3a4d6890e38a0b087767f3a7f
2013-08-31 05:46:42 +00:00
mistachkin 3fb4b6df07 Fix harmless MSVC compiler warning with MEMDEBUG defined.
FossilOrigin-Name: b48cfd2dfca70091a52deeeee16619237e1c270b
2013-08-31 05:13:22 +00:00
mistachkin 9f11ef1232 Improve the consistency of the diagnostic messages on Windows.
FossilOrigin-Name: c6f174a0cb27fe79740fffc7ce51081ec52a5dbd
2013-08-31 02:48:56 +00:00
mistachkin d95a3d3527 Add support for Cygwin when handling temporary file names. Improve error codes and diagnostic messages for temporary file name handling on Windows. Rename winConvertUtf8Filename to winConvertFromUtf8Filename. Improve placement and comments for forward function declarations.
FossilOrigin-Name: a411df725153119acb3bcf44fb71deecaa307887
2013-08-30 21:52:38 +00:00
dan ad4c7aa10f Fix compiler warnings in analyze.c.
FossilOrigin-Name: 5bbd2ccb3d2d6286fd667dac2ab658d6b89640a6
2013-08-30 20:19:52 +00:00
mistachkin 79e8445f63 Fix comment typo in analyze.c. No changes to code.
FossilOrigin-Name: dbc31750440226702fbf88f1bf6140ef403c9be1
2013-08-30 19:59:48 +00:00
drh e56dd3ad7b Fix comment typos in the where.c module. No code changes.
FossilOrigin-Name: 1e0b77cf0edf3d26f76d83aa5466e9ec0e60a710
2013-08-30 17:50:35 +00:00
drh f46af73720 If the cost of two whereLoop objects is the same in every way except that
one has fewer expected output rows than the other, then choose the one with
fewer output rows.

FossilOrigin-Name: 79e458ef7acfddbc189163e3e958da529becb130
2013-08-30 17:35:44 +00:00
drh 77a3fdc1b0 Add the SQLITE_MINIMUM_FILE_DESCRIPTOR compile-time option, for control over
exactly which low-numbered file descriptors SQLite will use.

FossilOrigin-Name: ba5190534330a25722eeb7ea9c42da7a6d146014
2013-08-30 14:24:12 +00:00
dan 43398081a8 Add a test for fts4 unicode61 option remove_diacritics=0.
FossilOrigin-Name: 6bf7ae6ff6b18712544ddeafb6848b3b27ff22d2
2013-08-30 13:29:51 +00:00
drh 5128d009c6 Improvements to the robust_open() logic in the unix VFS so that if an attempt
is made to open a repository on file descriptors 0, 1, or 2, and blocking
that file descriptor by opening it on /dev/null fails, then the open will
fail.

FossilOrigin-Name: d9c018f8155ab48df8e0e02519bba50588fe49fc
2013-08-30 06:20:23 +00:00
drh 00ea0e1133 Make the unix VFS defensive against the error of having a database file open
on file descriptors 1 or 2, as an error message might easily be written onto
those file descriptors and thus overwrite and corrupt the database.

FossilOrigin-Name: 30d38cc44904d93508b87e373b2f45d5f93e556b
2013-08-29 23:36:49 +00:00
drh 35a0379a05 Change the unix VFS so that it refuses to open a database file using
a file descriptor less than 3.

FossilOrigin-Name: 66dddda06898abbf97fe0ac6a10ce1527ca8605e
2013-08-29 23:34:53 +00:00
drh 0c9a8e345e Never leave an open file descriptor pointing into the middle of the
database file if the file descriptor number is 2 or less.

FossilOrigin-Name: 3426673e4659eb68dbd14a3e41d4620d748432db
2013-08-29 21:26:26 +00:00
dan 8bff07a55f Restore fix [f15591f802], which was accidentally clobbered by the stat4 merge.
FossilOrigin-Name: d4b6ad3333cc3bad500c2ebf7a6ea552b6762b69
2013-08-29 14:56:14 +00:00
dan cd40abb297 Candidate fix for [9f2eb3abac]: Have the whereShortCut() planner ignore indexes with more than four columns.
FossilOrigin-Name: c1152bdcbb5ac185f743015fff63769effa81b4b
2013-08-29 10:46:05 +00:00
mistachkin 1d406e0dfd Small enhancements to unit testing infrastructure.
FossilOrigin-Name: 9229aeb361f9805894321327d05aba855b8799f3
2013-08-29 01:09:14 +00:00
mistachkin 8bcd3fa75a Enable finer control of optimizations when compiling with the MSVC makefile. Also, several modularity enhancements to the MSVC makefile.
FossilOrigin-Name: 6c709338bc77fbed24a2597eabd88dd8c29b38d7
2013-08-29 01:03:38 +00:00
dan 1d2b70e3d2 Re-enable test file wild001.test.
FossilOrigin-Name: 4f182ddc36944fa54f1a34c1f0527db0ebb39c96
2013-08-28 19:01:07 +00:00
drh e4f9b9b7c0 Add the win32-longpath VFS allowing windows filenames up to 32K characters in
length.  Remove unused code when -DSQLITE_MAX_MMAP_SIZE=0.  Fix some
compiler warnings on windows.

FossilOrigin-Name: 12d0a8859de0a9d823997cfeccc77bd572cb6d13
2013-08-28 18:18:12 +00:00
mistachkin fe27b08934 Update list of supported Tcl shells to include 8.6. Remove stray OS2 references.
FossilOrigin-Name: ecd52ccf650ce2a4ab93c7c482289c1bc4768eeb
2013-08-28 18:06:26 +00:00
mistachkin 3259fe7910 Fix a couple comments.
FossilOrigin-Name: 945cb89ecb92a6c2075b3e58ce1ba3d419b1b6ca
2013-08-28 17:59:38 +00:00
drh d41d39f24d In the query optimizer, when converting BETWEEN and LIKE/GLOB expressions
into simpler forms for processing, be sure to transfer the LEFT JOIN markings.
Fix for ticket [bc878246eafe0f52c].

FossilOrigin-Name: caab361ebee5f5c3fdafd9b1abe3d1ab7c5b4db9
2013-08-28 16:27:01 +00:00
drh 38e587779d Increase the version number to 3.8.1 due to the addition of STAT4 support.
FossilOrigin-Name: 41c089e2a21f52b3d6d850eccba60be17010c9fe
2013-08-28 13:46:09 +00:00
drh 868ccf2679 Fix an off-by-one error that causes a quoted empty string at the end of
a CRNL-terminated line of CSV input to be misread by the shell.

FossilOrigin-Name: b5617e4fdadc4cded93c985008e90982dd48bc3b
2013-08-28 13:33:40 +00:00
drh f7f8de5fb2 Add a test case for empty quoted field in CSV import in the shell.
FossilOrigin-Name: 3df56e849164811117f9ac8ee2aee1eee188bb96
2013-08-28 11:57:52 +00:00
drh 6d57bbfe25 Label a certain branch as NEVER() only for non-STAT3/4 builds.
FossilOrigin-Name: b5ccf6e995ac2fe010f49d46d40b487ddbd28e5a
2013-08-28 11:43:49 +00:00
mistachkin 70e9ffa3bb In the win32longpath test, move the journal mode change down where it was intended to be.
FossilOrigin-Name: 5cead293bbbcddd7d0976db41133e40704efcc99
2013-08-28 07:42:43 +00:00
mistachkin 3741827ea1 Support database file names longer than 260 characters using the new 'win32-longpath' VFS variant.
FossilOrigin-Name: 37e85e444cde18f061049437980b965d4485f43c
2013-08-28 05:49:39 +00:00
mistachkin b324bc79e9 Make names of private functions in the Win32 VFS consistent. Fix comment typo in Win32 mutex implementation.
FossilOrigin-Name: c3b82c5bf97cfb35544c5b1fbcdf7b9c4827d1cf
2013-08-28 02:37:29 +00:00
mistachkin 533fb6de5b Remove hard-coding of the directory separator in the Win32 VFS. Fixes to OSTRACE macros.
FossilOrigin-Name: fc98092f4bd42d64059024f09547904c1d70a517
2013-08-28 02:26:48 +00:00
mistachkin f64188910d Fix several harmless compiler warnings. Fix a couple compiler issues with the shell.
FossilOrigin-Name: 8917e9f9a0802cbfb6f33e2ab1c2f98e4df5babd
2013-08-28 01:54:12 +00:00
drh 1435a9a126 Adjust ANALYZE for improved test coverage. Use the SQLITE_ENABLE_STAT3_OR_STAT4
macro (created in sqliteInt.h) to conditionally include code, instead of 
a boolean specifying both macros separately.

FossilOrigin-Name: 67a9a392edd62ef5a5a1ad3010b20a39b285793d
2013-08-27 23:15:44 +00:00
drh 9fecc546cb Reduce the amount of code run and memory used for ANALYZE in the common case
where neither STAT3 and STAT4 are enabled.

FossilOrigin-Name: 9d1424c91a21ed740aca53e437b8f7c1f0823c03
2013-08-27 20:16:48 +00:00
dan 0dd8b87955 Update sqlite3.pc.in to use @PACKAGE_VERSION@ instead of @RELEASE@.
FossilOrigin-Name: 2460dfd8825d251e622e866e8dc1c0bf7fe7ec9f
2013-08-27 15:41:09 +00:00
drh 59b08dd449 In the ANALYZE command implementation make statInit() a 2-value function
since the 3rd parameter was always the same constant.

FossilOrigin-Name: 959bb5acdc3b4e2b481e3c38f20867131bfc9dbc
2013-08-27 14:14:14 +00:00
mistachkin 4496a2329a Preparation for further Windows path name handling changes.
FossilOrigin-Name: ec99224b0c9cf1ccd64b3dc93252556d888e93a3
2013-08-26 23:18:57 +00:00
drh 2f53b90665 Merge the STAT4 capability into trunk.
FossilOrigin-Name: a32af0abe5fa6d570604fa3534e8230d5b6042fc
2013-08-26 23:18:06 +00:00
mistachkin 31706a2d94 Change MAX_PATH related defines to use character lengths where WCHARs are used.
FossilOrigin-Name: 0a497083e915520c0807cb6611264b1a35ff62b7
2013-08-26 20:45:50 +00:00
mistachkin 09b404419a Merge updates from trunk.
FossilOrigin-Name: 9d6860098f96efc7ea60e2d6116fb7d0e2685a55
2013-08-26 19:36:18 +00:00
dan 4dd5144366 Fix for builds with both SQLITE_OMIT_WAL and SQLITE_MAX_MMAP_SIZE=0 defined.
FossilOrigin-Name: edd5dbdc3239fc88799b822941603fcc828ecbb6
2013-08-26 14:30:25 +00:00
mistachkin e49d98fb0a Several modifications to the use of the MAX_PATH macro on Windows to improve consistency.
FossilOrigin-Name: bda4c47df8e80b4cc9e8aac8fd74482869f96107
2013-08-24 23:55:01 +00:00
mistachkin b5ca3cbcd3 Fix a couple compilation issues on Unix.
FossilOrigin-Name: 25b029d8f32440a94ef8af45153423f6702d7431
2013-08-24 01:12:03 +00:00
mistachkin e98844f723 Unify the result of PRAGMA mmap_size when mmap support is disabled.
FossilOrigin-Name: 032c31593d6f569842830cac6222362be68b2084
2013-08-24 00:59:24 +00:00
drh 92707acfd0 Adjustments to #ifdefs in analyze.c to all a clean compile with no
extra code with both ENABLE_STAT3 and ENABLE_STAT4 and with neither.

FossilOrigin-Name: f86b75b6c7290ee6ddb3636090b00e99fc68c45e
2013-08-17 18:57:15 +00:00
dan 0e8194a9c7 Add a test for the problem fixed by [91733bc485].
FossilOrigin-Name: 5c591104813a7e55e59f4f557cbb3e500fa817c2
2013-08-16 17:46:49 +00:00
drh 202ca9075f In sqlite3Stat4ProbeSetValue() change a local variable name iVar to iBindVar
to avoid confusion with iVal, and fix a place where the name was actually
confused.

FossilOrigin-Name: 91733bc4856034c10bc2ba0acdae1970b05d62b9
2013-08-16 17:18:02 +00:00
drh cf9f83dca2 Merge the fork that resulted from a check-in race.
FossilOrigin-Name: b7fe4f362bdf7b233a7b09eb9ce16d296165f82a
2013-08-16 14:51:32 +00:00
drh 0e1f0029c0 Fix valueFromExpr() so that it returns SQLITE_NOMEM following an OOM when
changing text encodings.  Also fix some asserts to accommodate OOM errors.

FossilOrigin-Name: dc1ccd09c443cebc4731dbe1a0dea84a9ccf6a9b
2013-08-16 14:49:00 +00:00
dan 22d73b1cbe Fixes for test code that was not working with utf16 databases. Run the analyze*.test scripts as part of the 'utf16' permutation test.
FossilOrigin-Name: fe99494d99df95f699ffab07b1e212800b5ff00d
2013-08-16 14:48:23 +00:00
dan 585c823256 Add extra tests. No code changes.
FossilOrigin-Name: 949127d53e0a907ed6f73c6828637d94b265468c
2013-08-16 14:23:02 +00:00
dan c367d4c052 Avoid buffer overreads and false OOM error reports that could be caused by corrupted sample records in the sqlite_stat4 table.
FossilOrigin-Name: 9f85b6a52a0b9b1524daa6f24d85257e7f591e95
2013-08-16 14:09:43 +00:00
drh 61b3440603 Fix a potential segfault following an OOM while running ANALYZE.
FossilOrigin-Name: 0118797823c9093e68113578f3f3aae65de41453
2013-08-16 13:34:50 +00:00
drh d94f512f58 Merge recent trunk changes into the STAT4 branch.
FossilOrigin-Name: c69b512af276a438399747af22659415af3a5d4d
2013-08-16 12:26:33 +00:00
dan 0adbed8a60 Fix a crash that can occur if the sqlite_stat3 or sqlite_stat4 table is corrupt.
FossilOrigin-Name: d51df8a8fcc31c37f6e1c9612204af5738ed865e
2013-08-15 19:56:32 +00:00
dan af2583c83c Fix a crash that can occur following an OOM fault.
FossilOrigin-Name: 9f80b2687012ab7c4d6d654fe19f40878bd78bd8
2013-08-15 18:43:21 +00:00
dan 3bc9f74fe9 Change some assert() statements in vdbe.c to ensure that a memory cell used to store a VdbeCursor object is not also used for some other purpose.
FossilOrigin-Name: 71070c9fce86103f174220e07771df99b2e01405
2013-08-15 16:18:39 +00:00
drh f0459fc410 Make sure the ANALYZE command allocates enough VDBE registers.
FossilOrigin-Name: 46fec9b1a1c4616df5a634dbf9235bd13408d3a9
2013-08-15 16:15:00 +00:00
dan 1f616ad8fa Add tests for sqlite_stat4 sample selection. And a fix for the same.
FossilOrigin-Name: 1fb4d9d6f2675515feb8e3d971bbd54716372549
2013-08-15 14:39:09 +00:00
dan f00e902580 Change the way ANALYZE works to use a single cursor when scanning indices.
FossilOrigin-Name: bdce612b35193abf72de1a563ea7962375b3574e
2013-08-14 19:54:12 +00:00
dan 8ad169abb4 If ENABLE_STAT3 is defined but ENABLE_STAT4 is not, have ANALYZE create and populate the sqlite_stat3 table instead of sqlite_stat4.
FossilOrigin-Name: cca8bf4372ab7a0258aa5c9397818415c6cf0abf
2013-08-12 20:14:04 +00:00
dan 86f69d98d2 If there is data in both the sqlite_stat4 and sqlite_stat3 tables for a single index, ignore the sqlite_stat3 records.
FossilOrigin-Name: 2a41736728d83a777ea8112da927cb047ec6684e
2013-08-12 17:31:32 +00:00
drh 6b0ae91930 Handle a NULL input to decodeIntArray() that can result from a prior OOM.
FossilOrigin-Name: fa1588adab6759fd3d1be02524aa19a0d1c6adaa
2013-08-12 17:00:08 +00:00
dan 0106e378f1 Re-enable reading from the sqlite_stat3 table (as well as sqlite_stat4).
FossilOrigin-Name: 6d45078e621526fc2bac0eaefbb0f9602b9a8ec5
2013-08-12 16:34:32 +00:00
dan 5133c78cae Fix a bug in calculating the average number of entries for keys not present in the sqlite_stat4 table.
FossilOrigin-Name: ec3ffb174844406a6186c3dcc41b76d0331b502c
2013-08-12 11:21:10 +00:00
dan 568cd51b79 Fix minor problems caused by adding the rowid to the records in stat4.
FossilOrigin-Name: 088d1ff94890ada50d43e6a366a58167ec5a8e96
2013-08-12 09:29:04 +00:00
dan dd6e1f193e Add the rowid field to the end of sample records stored in the sqlite_stat4 table.
FossilOrigin-Name: 3a5e8ab7ddbe1d943b35ef329fe4e5a1bfdb0d9d
2013-08-10 19:08:30 +00:00
dan 84d4fcc52d Fix a couple of typos in a comment in analyze.c. No code changes.
FossilOrigin-Name: 5bcccb93df98f5dfee0ea4d797b07fe0257258a9
2013-08-09 19:04:07 +00:00
drh c8af850479 Update the header comment on analyze.c to describe the sqlite_stat4 table
format.

FossilOrigin-Name: 4d97809d6b29809f12d753043bda1976bdb1bd3b
2013-08-09 14:07:55 +00:00
dan b3c02e210f Fix problems in estimating the number of rows visited by a range query using sqlite_stat4 data when the column subject to the range query is not the leftmost of the index.
FossilOrigin-Name: 9228aaf54dd2700c4f460f94f9c2309407578983
2013-08-08 19:38:40 +00:00
dan 84c309b6ae Use a binary search instead of a linear scan when comparing a sample key against data from the sqlite_stat4 table.
FossilOrigin-Name: e50dc30523210ba12324d5d8379503610f13aa34
2013-08-08 16:17:12 +00:00
dan ad45ed7414 Fix a segfault in "ALTER TABLE t1 ADD COLUMN b DEFAULT (-+1)". Also an assert() failure that could occur if SQLITE_ENABLE_STAT4 were not defined.
FossilOrigin-Name: 9fec3e38287067d60874530300fbeb602958c951
2013-08-08 12:21:32 +00:00
dan 6cb8d76ccb Fix a bug in using stat4 data to estimate the number of rows selected by a range constraint.
FossilOrigin-Name: f783938ea999731ea073cd2c78e278095f7bea6d
2013-08-08 11:48:57 +00:00
dan eea568d68e Replace variable Index.avgEq (average number of rows in keys for which there is no sample in sqlite_stat4) with vector Index.aAvgEq.
FossilOrigin-Name: 7b70b419c43b2c3b2daf11d833a1d60245bfaef5
2013-08-07 19:46:15 +00:00
dan 3d40759803 Merge latest trunk changes with this branch.
FossilOrigin-Name: 08f74c45ecf711a2373af578d44470add9082377
2013-08-07 18:42:27 +00:00
dan 32c693a6e6 Fix typos in a comment in analyze.c. No code changes.
FossilOrigin-Name: 812ed0c58fc5f729a2d4f16775fad6724cc367a6
2013-08-07 16:38:33 +00:00
dan 1f28eaddc4 Change the way samples for the sqlite_stat4 table are collected.
FossilOrigin-Name: 13ed5ac13562e7a39905d70fd47059f4d8001bba
2013-08-07 16:15:32 +00:00
drh 7ed103210d Fix the ".dump" command on the command-line shell so that it works for
"sqlite_stat4" in addition to "sqlite_stat1".

FossilOrigin-Name: 1e80c4b12dbb5beab422e2a33a8782ac9d767321
2013-08-07 16:04:27 +00:00
drh 4bfd4ad9a7 Remove the unused sqlite3Utf8to16() utility function.
FossilOrigin-Name: 9159b43eb2cb5d6ed18a5ad168fa27134fec2553
2013-08-07 15:57:24 +00:00
dan 87cd93215e When estimating the number of rows scanned using data from the sqlite_stat4 table, avoid allocating UnpackedRecord and KeyInfo structures until they are definitely required.
FossilOrigin-Name: 353950a5269fa439cc3e57b62e16558a84ea2557
2013-08-07 15:52:41 +00:00
dan ddc2d6e8f5 Fixes for builds without SQLITE_ENABLE_STAT4.
FossilOrigin-Name: 84999e27cc0d14b89d9fe024e29d287c69285369
2013-08-06 20:15:06 +00:00
dan 7a4192358a When possible, use the multi-column samples in sqlite_stat4 to estimate the number of index rows scanned by a query plan.
FossilOrigin-Name: 2973f5ca736c4a6f13c653d54b6a29d7cae8d0ed
2013-08-06 20:01:43 +00:00
dan c612970c9d Modify the vdbe code generated by ANALYZE to use fewer memory cells and cursor slots.
FossilOrigin-Name: 4a51cf289fad8aebc637b5f96488de18e861195d
2013-08-05 19:04:07 +00:00
dan e043201d3d Use N separate cursors when scanning an index with N columns to collect sqlite_stat4 data. This fixes a problem with collecting incorrect nEq values from multi-column indexes.
FossilOrigin-Name: 3a71afe67418ce00097cd9714c395fe9ff16f23b
2013-08-05 18:00:56 +00:00
dan c55521a60b Fix a couple of problems in code related to sqlite_stat4.
FossilOrigin-Name: badd24d987240db5528b37d1c177431617079f9b
2013-08-05 05:34:30 +00:00
dan f52bb8d385 Begin adding experimental sqlite_stat4 table. This commit is buggy.
FossilOrigin-Name: 2beea303a1d609cd2ff252412c50b966b9e5e8f1
2013-08-03 20:24:58 +00:00
71 changed files with 5391 additions and 1499 deletions
+34 -7
View File
@@ -94,6 +94,14 @@ WIN32HEAP = 0
DEBUG = 0
!ENDIF
# Enable use of available compiler optimizations? Normally, this should be
# non-zero. Setting this to zero, thus disabling all compiler optimizations,
# can be useful for testing.
#
!IFNDEF OPTIMIZATIONS
OPTIMIZATIONS = 2
!ENDIF
# Check for the predefined command macro CC. This should point to the compiler
# binary for the target platform. If it is not defined, simply define it to
# the legacy default value 'cl.exe'.
@@ -343,11 +351,15 @@ TCLSH_CMD = tclsh85
# Compiler options needed for programs that use the readline() library.
#
!IFNDEF READLINE_FLAGS
READLINE_FLAGS = -DHAVE_READLINE=0
!ENDIF
# The library that programs using readline() must link against.
#
!IFNDEF LIBREADLINE
LIBREADLINE =
!ENDIF
# Should the database engine be compiled threadsafe
#
@@ -397,17 +409,30 @@ RCC = $(RCC) $(OPT_FEATURE_FLAGS)
TCC = $(TCC) $(OPTS)
RCC = $(RCC) $(OPTS)
# If symbols are enabled, enable PDBs.
# If debugging is enabled, disable all optimizations and enable PDBs.
# If compiling for debugging, add some defines.
!IF $(DEBUG)>0
TCC = $(TCC) -Od -D_DEBUG
BCC = $(BCC) -Od -D_DEBUG
TCC = $(TCC) -D_DEBUG
BCC = $(BCC) -D_DEBUG
RCC = $(RCC) -D_DEBUG
!ELSE
TCC = $(TCC) -O2
BCC = $(BCC) -O2
!ENDIF
# If optimizations are enabled or disabled (either implicitly or
# explicitly), add the necessary flags.
!IF $(DEBUG)>0 || $(OPTIMIZATIONS)==0
TCC = $(TCC) -Od
BCC = $(BCC) -Od
!ELSEIF $(OPTIMIZATIONS)>=3
TCC = $(TCC) -Ox
BCC = $(BCC) -Ox
!ELSEIF $(OPTIMIZATIONS)==2
TCC = $(TCC) -O2
BCC = $(BCC) -O2
!ELSEIF $(OPTIMIZATIONS)==1
TCC = $(TCC) -O1
BCC = $(BCC) -O1
!ENDIF
# If symbols are enabled (or compiling for debugging), enable PDBs.
!IF $(DEBUG)>0 || $(SYMBOLS)!=0
TCC = $(TCC) -Zi
BCC = $(BCC) -Zi
@@ -465,7 +490,9 @@ LTLIBS = $(LTLIBS) $(LIBICU)
!ENDIF
# nawk compatible awk.
!IFNDEF NAWK
NAWK = gawk.exe
!ENDIF
# You should not have to change anything below this line
###############################################################################
+1 -1
View File
@@ -1 +1 @@
3.8.0.1
3.8.1
Vendored
+27 -38
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.8.0.1.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.1.
#
# 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.8.0.1'
PACKAGE_STRING='sqlite 3.8.0.1'
PACKAGE_VERSION='3.8.1'
PACKAGE_STRING='sqlite 3.8.1'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
@@ -874,7 +874,6 @@ TEMP_STORE
BUILD_EXEEXT
SQLITE_OS_UNIX
SQLITE_OS_WIN
SQLITE_OS_OS2
TARGET_EXEEXT
TCL_VERSION
TCL_BIN_DIR
@@ -1484,7 +1483,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.8.0.1 to adapt to many kinds of systems.
\`configure' configures sqlite 3.8.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1549,7 +1548,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.8.0.1:";;
short | recursive ) echo "Configuration of sqlite 3.8.1:";;
esac
cat <<\_ACEOF
@@ -1665,7 +1664,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.8.0.1
sqlite configure 3.8.1
generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1679,7 +1678,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.8.0.1, which was
It was created by sqlite $as_me 3.8.1, which was
generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@
@@ -3733,13 +3732,13 @@ if test "${lt_cv_nm_interface+set}" = set; then
else
lt_cv_nm_interface="BSD nm"
echo "int some_variable = 0;" > conftest.$ac_ext
(eval echo "\"\$as_me:3736: $ac_compile\"" >&5)
(eval echo "\"\$as_me:3735: $ac_compile\"" >&5)
(eval "$ac_compile" 2>conftest.err)
cat conftest.err >&5
(eval echo "\"\$as_me:3739: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval echo "\"\$as_me:3738: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
(eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
cat conftest.err >&5
(eval echo "\"\$as_me:3742: output\"" >&5)
(eval echo "\"\$as_me:3741: output\"" >&5)
cat conftest.out >&5
if $GREP 'External.*some_variable' conftest.out > /dev/null; then
lt_cv_nm_interface="MS dumpbin"
@@ -4961,7 +4960,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
echo '#line 4964 "configure"' > conftest.$ac_ext
echo '#line 4963 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -6830,11 +6829,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:6833: $lt_compile\"" >&5)
(eval echo "\"\$as_me:6832: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:6837: \$? = $ac_status" >&5
echo "$as_me:6836: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7169,11 +7168,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7172: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7171: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
echo "$as_me:7176: \$? = $ac_status" >&5
echo "$as_me:7175: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -7274,11 +7273,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7277: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7276: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7281: \$? = $ac_status" >&5
echo "$as_me:7280: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -7329,11 +7328,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
(eval echo "\"\$as_me:7332: $lt_compile\"" >&5)
(eval echo "\"\$as_me:7331: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
echo "$as_me:7336: \$? = $ac_status" >&5
echo "$as_me:7335: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -10142,7 +10141,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 10145 "configure"
#line 10144 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10238,7 +10237,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
#line 10241 "configure"
#line 10240 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12257,7 +12256,7 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
#
for ac_prog in tclsh8.5 tclsh
for ac_prog in tclsh8.6 tclsh8.5 tclsh
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
@@ -12713,21 +12712,12 @@ else
TARGET_EXEEXT=$config_TARGET_EXEEXT
fi
if test "$TARGET_EXEEXT" = ".exe"; then
if test $OS2_SHELL ; then
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=0
SQLITE_OS_OS2=1
CFLAGS="$CFLAGS -DSQLITE_OS_OS2=1"
else
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
SQLITE_OS_OS2=0
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
fi
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
else
SQLITE_OS_UNIX=1
SQLITE_OS_WIN=0
SQLITE_OS_OS2=0
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi
@@ -12736,7 +12726,6 @@ fi
##########
# Figure out all the parameters needed to compile against Tcl.
#
@@ -14032,7 +14021,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.8.0.1, which was
This file was extended by sqlite $as_me 3.8.1, which was
generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14085,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.8.0.1
sqlite config.status 3.8.1
configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+4 -14
View File
@@ -139,7 +139,7 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back?
#
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.5 tclsh], none)
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh8.5 tclsh], none)
if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used.
@@ -340,28 +340,18 @@ else
TARGET_EXEEXT=$config_TARGET_EXEEXT
fi
if test "$TARGET_EXEEXT" = ".exe"; then
if test $OS2_SHELL ; then
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=0
SQLITE_OS_OS2=1
CFLAGS="$CFLAGS -DSQLITE_OS_OS2=1"
else
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
SQLITE_OS_OS2=0
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
fi
SQLITE_OS_UNIX=0
SQLITE_OS_WIN=1
CFLAGS="$CFLAGS -DSQLITE_OS_WIN=1"
else
SQLITE_OS_UNIX=1
SQLITE_OS_WIN=0
SQLITE_OS_OS2=0
CFLAGS="$CFLAGS -DSQLITE_OS_UNIX=1"
fi
AC_SUBST(BUILD_EXEEXT)
AC_SUBST(SQLITE_OS_UNIX)
AC_SUBST(SQLITE_OS_WIN)
AC_SUBST(SQLITE_OS_OS2)
AC_SUBST(TARGET_EXEEXT)
##########
+77 -70
View File
@@ -1,12 +1,12 @@
C Version\s3.8.0.1
D 2013-08-29T17:35:01.986
C Increase\sthe\snumber\sof\sbits\savailable\sin\sExpr.flags.\s\sOther\stweaks\saimed\sat\nmaking\sexpression\sprocessing\smore\srobust.
D 2013-09-12T16:50:49.178
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc e9f41f89111627baaabd95cab4988b8d1c3e47c9
F Makefile.msc a97163524522cd829cb91bcf900d07608e025502
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
F VERSION 087a4ef56b220aeb0fbef8ae45871be9668cd970
F VERSION a8d1f6839521130dc73c5408cdd24bcfd791df34
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -38,8 +38,8 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 9af276330ddd63041537a88323705690d02df76e x
F configure.ac 81c43d151d0b0e406be056394cc9ff4cb3fd0444
F configure d9bb8485d40dd905e09c895692a0699628abace8 x
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
@@ -156,40 +156,40 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
F src/analyze.c a33fcb0b3a399d966951feb9f32115106b3ecc2e
F src/attach.c fea00cab11c854646a27641a263f5876569a51f9
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
F src/analyze.c d322972af09e3f8debb45f420dfe3ded142b108b
F src/attach.c 4a2b6a6d9b5f9fd55a8b59488ff7929fef73a195
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c b7cbb0bcc61cbf1e0ed3cfcc79ee12ffcf4f469e
F src/btree.c b9b57df546df2636294bfb21a986f5707b417df2
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
F src/btreeInt.h 51cf220a9b9223354770883e93a859dc377aa27f
F src/build.c f99a715ff9290996b579d5e1ec8e94239dc9ae5e
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
F src/build.c f63e8929c7f89c0074fbc74929bc946ea117b2f8
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94
F src/expr.c 6bab61c757c4c4c94a92e98d507025d5d18afd3c
F src/delete.c 2dc64ca360b7d7da481183ea920a813a0c203c97
F src/expr.c 7f93e51fd7ca0d3ea1be2715a29c86a69e7b1e93
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
F src/func.c d7be77897c91d5b9887beb372f1e6deb515c92af
F src/fkey.c be866cd8c4fa6cae98ba33109578fd1a3311ee5b
F src/func.c 7650d35651bb0ca903d24f4e5e944bfdaac9f152
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c a66bcdc956145369c1a876709f47f69476973e15
F src/insert.c a271771db927873c850da8928d6ee9fc058fb9fe
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c dc02c7c118d58049e0cccc6c9c47c0a4d3e2bcda
F src/main.c 35931467ec026b05babb279cb8a573e62f6fe1a3
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
F src/mem2.c e307323e86b5da1853d7111b68fd6b84ad6f09cf
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 0025308a93838022bd5696cf9627ff4e40b19918
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
@@ -197,36 +197,36 @@ F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
F src/mutex_w32.c 32a9b3841e2d757355f0012b860b1bc5e01eafa0
F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 9eafa5458cf2ff684ddccff82c9bb113c7cad847
F src/os_win.c 1d84f2079d9b91f91a4b5dbfa5e08f1b1a0ed0ff
F src/os_unix.c 243fb37f47dc072fc59839ea241ff0a17c8d76e6
F src/os_win.c 0e73f891dd806b82a76d4e19179c532f02236b86
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
F src/parse.y 27c6b4138497d6f8360ba7847da6ed48033f957f
F src/parse.y a97566d6da75075589a7c716d1bda14b586cf8da
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
F src/pragma.c dc9ceab9b361e3fbd461ebaa7fb8003233e20725
F src/pragma.c 3aa3d8c8623b7b71c5b1bfb72dcc31fb0c25665f
F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
F src/resolve.c 9d53899cc6e1f4ec0b4632d07e97d57827bf63b9
F src/resolve.c d336be12493bb376c6756c214379c727cd8c01a8
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 8b148eb851f384412aea57091659d14b369918ca
F src/shell.c 0fb2ce9876596e99ed64caffaec6c4bf224cb22d
F src/sqlite.h.in bd1451ba1ab681022a53bccc3c39580ba094a3ff
F src/select.c d96bcdbc2e7de89cb72febeccd232746f67839fd
F src/shell.c d920a891ca09b8bd262cced7fb0ab9d723f7a747
F src/sqlite.h.in ec40aa958a270416fb04b4f72210357bf163d2c5
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 124e4b19cd5533116909ccf203bdcdd04a28f99a
F src/sqliteInt.h e4cb0c8700ca77889570bf30cf75a5c56f297615
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 659dad8ef30b54831306a244b43e37af4725a444
F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa
F src/test1.c 26226cfd2b6dc3f77d2eb27f07ffcf236b4e728b
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -239,18 +239,18 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
F src/test_config.c 95bb33e9dcaa340a296c0bf0e0ba3d1a1c8004c0
F src/test_config.c 3d148e338b575bd937f7746824f36a9c6682d238
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
F src/test_func.c 3a8dd37c08ab43b76d38eea2836e34a3897bf170
F src/test_func.c f8235719dff4bf9ffee04c55a190af8782ce9ab5
F src/test_hexio.c abfdecb6fa58c354623978efceb088ca18e379cd
F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
F src/test_malloc.c a105801222c0514f8befa2a1712a95505cce099a
F src/test_malloc.c eba4e1c5847cc98e7edc98f62265cd2abafba7a6
F src/test_multiplex.c 5d691eeb6cb6aa7888da28eba5e62a9a857d3c0f
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
@@ -273,41 +273,44 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e
F src/update.c 7f3fe64d8f3b44c44a1eac293f0f85f87c355b7a
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
F src/update.c f5182157f5d0d0a97bc5f5e3c9bdba0dfbe08f08
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
F src/vdbe.c d37aee2c89e2a589f2b1599e0178eb17a08a3ccb
F src/vdbe.c a393a94c0d77b86c7c4ad2cfb43ec4ba278d9596
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
F src/vdbeInt.h cbe71b8b36d8b3bba5709cc3f436c7e3b47b7b08
F src/vdbeapi.c 96b24b946cf21894f63d9393e821baa2f0a80979
F src/vdbeaux.c c7fe2695e256dbf254113c4fe90d3ec9aabe3bbe
F src/vdbeaux.c 88beca92f2ed0bbe2c6f87946d0e999a6807ea1b
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
F src/vdbemem.c 61d5ddb8e4d4e14f625062bf5bcc7ce08bb20af3
F src/vdbemem.c 817ce21ab4ca57f902619bb8fef3f8a51bbd0ed8
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
F src/vtab.c 165ce0e797c2cd23badb104c9f2ae9042d6d942c
F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
F src/where.c a9ec7caba7697f152bd34853b98500dd54c4b240
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
F src/where.c b5d59b899b85aa03800905ecdc0a17565d51a6ab
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783
F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748
F test/alter.test 775a1dded3f8247983c9a3e767b011d9a5114442
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
F test/alter4.test 8e93bf7a7e6919b14b0c9a6c1e4908bcf21b0165
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae
F test/analyze3.test 53cfd07625d110e70b92b57a6ff656ea844dfbee
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
F test/analyze5.test 3e57f192307be931f9ab2f6ff456f9063358ac77
F test/analyze6.test cdbf9887d40ab41301f570fe85c6e1525dd3b1c9
F test/analyze7.test 7de3ab66e1981303e783102a012d62cb876bf1d5
F test/analyze8.test ea4972c76820ac8d6a0754e6f5b851292f0f5a61
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
F test/analyze9.test ed70f0c10502f6bcd6e1ec347edc3c0e114f4b53
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
@@ -319,7 +322,7 @@ F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49
F test/auth.test 9bea29041871807d9f289ee679d05d3ed103642f
F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
@@ -411,7 +414,7 @@ F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9
F test/dbstatus.test 207e5b63fcb7b9c3bb8e1fdf38ebd4654ad0e54b
F test/dbstatus.test aee30c3f337e6c217ff06df59fb8fe6e6448dce2
F test/dbstatus2.test 10418e62b3db5dca070f0c3eef3ea13946f339c2
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
@@ -459,6 +462,7 @@ F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 0bf64f2d19ad80433ca0b24edbf604a18b353d5f
F test/fkey6.test c555f7fc45d842cc84b0d3ff93951ce2b8c25fc8
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
@@ -555,7 +559,7 @@ F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2
F test/fts4unicode.test 5fa8e0a7899d906d114345c605250ebfa9d8ed28
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test cd25cf605c5a345d038dc7b84232204c6a901c84
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
@@ -590,7 +594,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
F test/index6.test 6a754747f444fecb7f4ae50ce4ac7a0d269e090d
F test/index6.test e96324d8c1ade4b30a4c6cee14b1fc2e5a367cda
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
@@ -649,7 +653,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
F test/mallocA.test 47006c8d70f29b030652e251cb9d35ba60289198
F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
@@ -714,7 +718,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
F test/permutations.test 461ef4ea10db02cd421dfe5f988eac3e99b5cd9a
F test/permutations.test 72f4f8881d388163ddbbeec0a6ed812e863ea2e6
F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178
F test/pragma2.test 224f0381f9411a78ae685cac24c13656a62021b7
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@@ -778,11 +782,11 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
F test/sharedlock.test 927a4b6da11978c82b857dbdb20a932aad732123
F test/shell1.test 928547277d385038c696428e9d791cbbad098974
F test/shell1.test 474ed53bb461c4ba9b6468d3a74e86eb8ee0d9d0
F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a
F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
F test/shell5.test 946e620a41b64f90d45dcf91c36e8d408d435cfd
F test/shell5.test bfa21ecc173adcbc15db2c075baa468778f67f88
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
@@ -809,13 +813,13 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
F test/table.test 30423211108121884588d24d6776c7f38702ad7b
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 26670ed7a39cf2296a7f0a9e0a1d7bdb7abe936d
F test/tester.tcl 63b24679c75a952c51f924de2802b2b57cddd22d
F test/tester.tcl 5e97d1fe08f45fa3cc2320cee437e315c75ce995
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -865,7 +869,7 @@ F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
F test/tkt-bd484a090c.test 60460bf946f79a79712b71f202eda501ca99b898
F test/tkt-bdc6bbbb38.test fc38bb09bdd440e3513a1f5f98fc60a075182d7d
F test/tkt-c48d99d690.test ba61977d62ab612fc515b3c488a6fbd6464a2447
F test/tkt-cbd054fa6b.test 9c27ed07b333eed458e5d4543f91ecdcf05aeb19
F test/tkt-cbd054fa6b.test 06ccd57af3c0c7895d0f7dc844f13c51f8258885
F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
@@ -960,6 +964,7 @@ F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
@@ -1039,7 +1044,7 @@ F test/walro.test 6cc247a0cc9b36aeea2057dd28a922a1cdfbd630
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
F test/where.test da54153a4c1571ea1b95659e5bec8119edf786aa
F test/where.test 8d66dfbfd4d12816f74f854dbf67dee492c06267
F test/where2.test 76d5346f7edb2a6a0442dcf3e9d088ac6903e0b5
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
@@ -1048,16 +1053,17 @@ F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
F test/where8.test 6f95896633cf2d307b5263145b942b7d33e837c6
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test 167a89495715db4d6a7d1e6a1aadf934ddc06516
F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 136a7301512d72a08a272806c8767066311b7bc1
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
F tool/build-all-msvc.bat c55f64ca200308fb5fa5c1ee751ea95a13977b5a x
@@ -1076,7 +1082,7 @@ F tool/mkkeywordhash.c bb52064aa614e1426445e4b2b9b00eeecd23cc79
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
F tool/mksqlite3c.tcl a61fe62a2895ca6458c463fccf1211ca1c000fcf
F tool/mksqlite3c.tcl d344cc3144a0271cd853c5e3df36e9f31d78d619
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
F tool/mkvsix.tcl 0be7f7a591f1e83f9199cb82911b66668ca484c9
@@ -1106,9 +1112,10 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P c5857808c0707baa30994dd6aa3b9c93a74c0073
R f09fdab74837e6353df38f5d2273681e
T +sym-release *
T +sym-version-3.8.0.1 *
P 75a8a8c1b39725d36db627536d0c69401f8e0815
R 14e40117cf5ed4a868935b4adf8b8b0d
T *branch * expr-tuning
T *sym-expr-tuning *
T -sym-trunk *
U drh
Z 3c028394a3a00a433c82a9881b010566
Z e578fc31598c846285e1a40bbc280fc4
+1 -1
View File
@@ -1 +1 @@
352362bc01660edfbda08179d60f09e2038a2f49
579a512538528cf4bb4381ba393c5d9e7310086b
+1 -1
View File
@@ -687,7 +687,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
** can handle (i.e. not CURRENT_TIME etc.)
*/
if( pDflt ){
sqlite3_value *pVal;
sqlite3_value *pVal = 0;
if( sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal) ){
db->mallocFailed = 1;
return;
+1019 -519
View File
File diff suppressed because it is too large Load Diff
+3 -5
View File
@@ -379,8 +379,7 @@ attach_end:
void sqlite3Detach(Parse *pParse, Expr *pDbname){
static const FuncDef detach_func = {
1, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
detachFunc, /* xFunc */
@@ -401,8 +400,7 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
static const FuncDef attach_func = {
3, /* nArg */
SQLITE_UTF8, /* iPrefEnc */
0, /* flags */
SQLITE_UTF8, /* funcFlags */
0, /* pUserData */
0, /* pNext */
attachFunc, /* xFunc */
@@ -511,7 +509,7 @@ int sqlite3FixExpr(
Expr *pExpr /* The expression to be fixed to one database */
){
while( pExpr ){
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ) break;
if( ExprHasProperty(pExpr, EP_TokenOnly) ) break;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
if( sqlite3FixSelect(pFix, pExpr->x.pSelect) ) return 1;
}else{
+1
View File
@@ -2508,6 +2508,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->maxLeaf + 23 <= MX_CELL_SIZE(pBt) );
pBt->pPage1 = pPage1;
pBt->nPage = nPage;
assert( pPage1->leaf==0 || pPage1->leaf==1 );
return SQLITE_OK;
page1_init_failed:
+1 -1
View File
@@ -2024,7 +2024,7 @@ static void sqlite3ClearStatTables(
){
int i;
const char *zDbName = pParse->db->aDb[iDb].zName;
for(i=1; i<=3; i++){
for(i=1; i<=4; i++){
char zTab[24];
sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
+3 -3
View File
@@ -270,9 +270,9 @@ static int matchQuality(
}
/* Bonus points if the text encoding matches */
if( enc==p->iPrefEnc ){
if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){
match += 2; /* Exact encoding match */
}else if( (enc & p->iPrefEnc & 2)!=0 ){
}else if( (enc & p->funcFlags & 2)!=0 ){
match += 1; /* Both are UTF16, but with different byte orders */
}
@@ -406,7 +406,7 @@ FuncDef *sqlite3FindFunction(
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
pBest->zName = (char *)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->iPrefEnc = enc;
pBest->funcFlags = enc;
memcpy(pBest->zName, zName, nName);
pBest->zName[nName] = 0;
sqlite3FuncDefInsert(&db->aFunc, pBest);
+3 -1
View File
@@ -117,7 +117,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
#endif
#ifdef SQLITE_ENABLE_STAT3
#if defined(SQLITE_ENABLE_STAT4)
"ENABLE_STAT4",
#elif defined(SQLITE_ENABLE_STAT3)
"ENABLE_STAT3",
#endif
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
+2 -2
View File
@@ -536,7 +536,7 @@ void sqlite3GenerateRowDelete(
/* Do FK processing. This call checks that any FK constraints that
** refer to this table (i.e. constraints attached to other tables)
** are not violated by deleting this row. */
sqlite3FkCheck(pParse, pTab, iOld, 0);
sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0);
}
/* Delete the index and table entries. Skip this step if pTab is really
@@ -553,7 +553,7 @@ void sqlite3GenerateRowDelete(
/* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
** handle rows (possibly in other tables) that refer via a foreign key
** to the row just deleted. */
sqlite3FkActions(pParse, pTab, 0, iOld);
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
sqlite3CodeRowTrigger(pParse, pTrigger,
+34 -35
View File
@@ -596,7 +596,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
const char *z;
if( pExpr==0 ) return;
assert( !ExprHasAnyProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
assert( !ExprHasProperty(pExpr, EP_IntValue|EP_Reduced|EP_TokenOnly) );
z = pExpr->u.zToken;
assert( z!=0 );
assert( z[0]!=0 );
@@ -666,12 +666,12 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p==0 ) return;
/* Sanity check: Assert that the IntValue is non-negative if it exists */
assert( !ExprHasProperty(p, EP_IntValue) || p->u.iValue>=0 );
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
if( !ExprHasProperty(p, EP_TokenOnly) ){
/* The Expr.x union is never used at the same time as Expr.pRight */
assert( p->x.pList==0 || p->pRight==0 );
sqlite3ExprDelete(db, p->pLeft);
sqlite3ExprDelete(db, p->pRight);
if( !ExprHasProperty(p, EP_Reduced) && (p->flags2 & EP2_MallocedToken)!=0 ){
sqlite3DbFree(db, p->u.zToken);
}
if( ExprHasProperty(p, EP_MemToken) ) sqlite3DbFree(db, p->u.zToken);
if( ExprHasProperty(p, EP_xIsSelect) ){
sqlite3SelectDelete(db, p->x.pSelect);
}else{
@@ -734,10 +734,10 @@ static int dupedExprStructSize(Expr *p, int flags){
if( 0==(flags&EXPRDUP_REDUCE) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_FromJoin) );
assert( (p->flags2 & EP2_MallocedToken)==0 );
assert( (p->flags2 & EP2_Irreducible)==0 );
assert( !ExprHasProperty(p, EP_MemToken) );
assert( !ExprHasProperty(p, EP_Irreduce) );
if( p->pLeft || p->pRight || p->x.pList ){
nSize = EXPR_REDUCEDSIZE | EP_Reduced;
}else{
@@ -834,7 +834,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static);
pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken);
pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly);
pNew->flags |= staticFlag;
@@ -854,7 +854,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
}
/* Fill in pNew->pLeft and pNew->pRight. */
if( ExprHasAnyProperty(pNew, EP_Reduced|EP_TokenOnly) ){
if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly) ){
zAlloc += dupedExprNodeSize(p, flags);
if( ExprHasProperty(pNew, EP_Reduced) ){
pNew->pLeft = exprDup(db, p->pLeft, EXPRDUP_REDUCE, &zAlloc);
@@ -864,8 +864,7 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int flags, u8 **pzBuffer){
*pzBuffer = zAlloc;
}
}else{
pNew->flags2 = 0;
if( !ExprHasAnyProperty(p, EP_TokenOnly) ){
if( !ExprHasProperty(p, EP_TokenOnly) ){
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
pNew->pRight = sqlite3ExprDup(db, p->pRight, 0);
}
@@ -1175,7 +1174,7 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
/* If pWalker->u.i is 3 then any term of the expression that comes from
** the ON or USING clauses of a join disqualifies the expression
** from being considered constant. */
if( pWalker->u.i==3 && ExprHasAnyProperty(pExpr, EP_FromJoin) ){
if( pWalker->u.i==3 && ExprHasProperty(pExpr, EP_FromJoin) ){
pWalker->u.i = 0;
return WRC_Abort;
}
@@ -1278,7 +1277,7 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){
case TK_UMINUS: {
int v;
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
assert( v!=-2147483648 );
assert( v!=(-2147483647-1) );
*pValue = -v;
rc = 1;
}
@@ -1606,7 +1605,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
}else{
testcase( pParse->nQueryLoop>0 );
pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasAnyProperty(pX, EP_xIsSelect) ){
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
}
}
@@ -1675,7 +1674,7 @@ int sqlite3CodeSubselect(
** If all of the above are false, then we can run this code just once
** save the results, and reuse the same result on subsequent invocations.
*/
if( !ExprHasAnyProperty(pExpr, EP_VarSelect) ){
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
testAddr = sqlite3CodeOnce(pParse);
}
@@ -2615,7 +2614,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
testcase( op==TK_CONST_FUNC );
testcase( op==TK_FUNCTION );
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
}else{
pFarg = pExpr->x.pList;
@@ -2634,7 +2633,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** IFNULL() functions. This avoids unnecessary evalation of
** arguments past the first non-NULL argument.
*/
if( pDef->flags & SQLITE_FUNC_COALESCE ){
if( pDef->funcFlags & SQLITE_FUNC_COALESCE ){
int endCoalesce = sqlite3VdbeMakeLabel(v);
assert( nFarg>=2 );
sqlite3ExprCode(pParse, pFarg->a[0].pExpr, target);
@@ -2658,7 +2657,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
** loading.
*/
if( (pDef->flags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
assert( nFarg==1 );
assert( pFarg->a[0].pExpr!=0 );
@@ -2666,8 +2665,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
testcase( pDef->flags==SQLITE_FUNC_LENGTH );
pFarg->a[0].pExpr->op2 = pDef->flags;
testcase( (pDef->funcFlags&~SQLITE_FUNC_ENCMASK)
==SQLITE_FUNC_LENGTH );
pFarg->a[0].pExpr->op2 = pDef->funcFlags&~SQLITE_FUNC_ENCMASK;
}
}
@@ -2700,11 +2700,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
constMask |= (1<<i);
}
if( (pDef->flags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
}
}
if( pDef->flags & SQLITE_FUNC_NEEDCOLL ){
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
}
@@ -2845,9 +2845,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** WHEN x=eN THEN rN ELSE y END
**
** X (if it exists) is in pExpr->pLeft.
** Y is in pExpr->pRight. The Y is also optional. If there is no
** ELSE clause and no other term matches, then the result of the
** exprssion is NULL.
** Y is in the last element of pExpr->x.pList if pExpr->x.pList->nExpr is
** odd. The Y is also optional. If the number of elements in x.pList
** is even, then Y is omitted and the "otherwise" result is NULL.
** Ei is in pExpr->pList->a[i*2] and Ri is pExpr->pList->a[i*2+1].
**
** The result of the expression is the Ri for the first matching Ei,
@@ -2868,7 +2868,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert((pExpr->x.pList->nExpr % 2) == 0);
assert(pExpr->x.pList->nExpr > 0);
pEList = pExpr->x.pList;
aListelem = pEList->a;
@@ -2890,7 +2889,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** purposes and possibly overwritten. */
regFree1 = 0;
}
for(i=0; i<nExpr; i=i+2){
for(i=0; i<nExpr-1; i=i+2){
sqlite3ExprCachePush(pParse);
if( pX ){
assert( pTest!=0 );
@@ -2908,9 +2907,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3ExprCachePop(pParse, 1);
sqlite3VdbeResolveLabel(v, nextCase);
}
if( pExpr->pRight ){
if( (nExpr&1)!=0 ){
sqlite3ExprCachePush(pParse);
sqlite3ExprCode(pParse, pExpr->pRight, target);
sqlite3ExprCode(pParse, pEList->a[nExpr-1].pExpr, target);
sqlite3ExprCachePop(pParse, 1);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
@@ -3154,7 +3153,7 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
if( ExprHasAnyProperty(pExpr, EP_TokenOnly) ){
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
}else{
pFarg = pExpr->x.pList;
@@ -3820,8 +3819,8 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
if( pA==0||pB==0 ){
return pB==pA ? 0 : 2;
}
assert( !ExprHasAnyProperty(pA, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasAnyProperty(pB, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pA, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pB, EP_TokenOnly|EP_Reduced) );
if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
return 2;
}
@@ -4035,7 +4034,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
struct SrcList_item *pItem = pSrcList->a;
for(i=0; i<pSrcList->nSrc; i++, pItem++){
struct AggInfo_col *pCol;
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
if( pExpr->iTable==pItem->iCursor ){
/* If we reach this point, it means that pExpr refers to a table
** that is in the FROM clause of the aggregate query.
@@ -4130,7 +4129,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
*/
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
ExprSetIrreducible(pExpr);
pExpr->iAgg = (i16)i;
pExpr->pAggInfo = pAggInfo;
+89 -23
View File
@@ -682,6 +682,70 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
}
}
/*
** The second argument points to an FKey object representing a foreign key
** for which pTab is the child table. An UPDATE statement against pTab
** is currently being processed. For each column of the table that is
** actually updated, the corresponding element in the aChange[] array
** is zero or greater (if a column is unmodified the corresponding element
** is set to -1). If the rowid column is modified by the UPDATE statement
** the bChngRowid argument is non-zero.
**
** This function returns true if any of the columns that are part of the
** child key for FK constraint *p are modified.
*/
static int fkChildIsModified(
Table *pTab, /* Table being updated */
FKey *p, /* Foreign key for which pTab is the child */
int *aChange, /* Array indicating modified columns */
int bChngRowid /* True if rowid is modified by this update */
){
int i;
for(i=0; i<p->nCol; i++){
int iChildKey = p->aCol[i].iFrom;
if( aChange[iChildKey]>=0 ) return 1;
if( iChildKey==pTab->iPKey && bChngRowid ) return 1;
}
return 0;
}
/*
** The second argument points to an FKey object representing a foreign key
** for which pTab is the parent table. An UPDATE statement against pTab
** is currently being processed. For each column of the table that is
** actually updated, the corresponding element in the aChange[] array
** is zero or greater (if a column is unmodified the corresponding element
** is set to -1). If the rowid column is modified by the UPDATE statement
** the bChngRowid argument is non-zero.
**
** This function returns true if any of the columns that are part of the
** parent key for FK constraint *p are modified.
*/
static int fkParentIsModified(
Table *pTab,
FKey *p,
int *aChange,
int bChngRowid
){
int i;
for(i=0; i<p->nCol; i++){
char *zKey = p->aCol[i].zCol;
int iKey;
for(iKey=0; iKey<pTab->nCol; iKey++){
if( aChange[iKey]>=0 || (iKey==pTab->iPKey && bChngRowid) ){
Column *pCol = &pTab->aCol[iKey];
if( zKey ){
if( 0==sqlite3StrICmp(pCol->zName, zKey) ) return 1;
}else if( pCol->colFlags & COLFLAG_PRIMKEY ){
return 1;
}
}
}
}
return 0;
}
/*
** This function is called when inserting, deleting or updating a row of
** table pTab to generate VDBE code to perform foreign key constraint
@@ -706,7 +770,9 @@ void sqlite3FkCheck(
Parse *pParse, /* Parse context */
Table *pTab, /* Row is being deleted from this table */
int regOld, /* Previous row data is stored here */
int regNew /* New row data is stored here */
int regNew, /* New row data is stored here */
int *aChange, /* Array indicating UPDATEd columns (or 0) */
int bChngRowid /* True if rowid is UPDATEd */
){
sqlite3 *db = pParse->db; /* Database handle */
FKey *pFKey; /* Used to iterate through FKs */
@@ -734,6 +800,13 @@ void sqlite3FkCheck(
int i;
int isIgnore = 0;
if( aChange
&& sqlite3_stricmp(pTab->zName, pFKey->zTo)!=0
&& fkChildIsModified(pTab, pFKey, aChange, bChngRowid)==0
){
continue;
}
/* Find the parent table of this foreign key. Also find a unique index
** on the parent key columns in the parent table. If either of these
** schema items cannot be located, set an error in pParse and return
@@ -816,6 +889,10 @@ void sqlite3FkCheck(
SrcList *pSrc;
int *aiCol = 0;
if( aChange && fkParentIsModified(pTab, pFKey, aChange, bChngRowid)==0 ){
continue;
}
if( !pFKey->isDeferred && !(db->flags & SQLITE_DeferFKs)
&& !pParse->pToplevel && !pParse->isMultiWrite
){
@@ -889,6 +966,7 @@ u32 sqlite3FkOldmask(
return mask;
}
/*
** This function is called before generating code to update or delete a
** row contained in table pTab. If the operation is a DELETE, then
@@ -918,32 +996,16 @@ int sqlite3FkRequired(
}else{
/* This is an UPDATE. Foreign key processing is only required if the
** operation modifies one or more child or parent key columns. */
int i;
FKey *p;
/* Check if any child key columns are being modified. */
for(p=pTab->pFKey; p; p=p->pNextFrom){
for(i=0; i<p->nCol; i++){
int iChildKey = p->aCol[i].iFrom;
if( aChange[iChildKey]>=0 ) return 1;
if( iChildKey==pTab->iPKey && chngRowid ) return 1;
}
if( fkChildIsModified(pTab, p, aChange, chngRowid) ) return 1;
}
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
for(i=0; i<p->nCol; i++){
char *zKey = p->aCol[i].zCol;
int iKey;
for(iKey=0; iKey<pTab->nCol; iKey++){
Column *pCol = &pTab->aCol[iKey];
if( (zKey ? !sqlite3StrICmp(pCol->zName, zKey)
: (pCol->colFlags & COLFLAG_PRIMKEY)!=0) ){
if( aChange[iKey]>=0 ) return 1;
if( iKey==pTab->iPKey && chngRowid ) return 1;
}
}
}
if( fkParentIsModified(pTab, p, aChange, chngRowid) ) return 1;
}
}
}
@@ -1169,7 +1231,9 @@ void sqlite3FkActions(
Parse *pParse, /* Parse context */
Table *pTab, /* Table being updated or deleted from */
ExprList *pChanges, /* Change-list for UPDATE, NULL for DELETE */
int regOld /* Address of array containing old row */
int regOld, /* Address of array containing old row */
int *aChange, /* Array indicating UPDATEd columns (or 0) */
int bChngRowid /* True if rowid is UPDATEd */
){
/* If foreign-key support is enabled, iterate through all FKs that
** refer to table pTab. If there is an action associated with the FK
@@ -1178,9 +1242,11 @@ void sqlite3FkActions(
if( pParse->db->flags&SQLITE_ForeignKeys ){
FKey *pFKey; /* Iterator variable */
for(pFKey = sqlite3FkReferences(pTab); pFKey; pFKey=pFKey->pNextTo){
Trigger *pAction = fkActionTrigger(pParse, pTab, pFKey, pChanges);
if( pAction ){
sqlite3CodeRowTriggerDirect(pParse, pAction, pTab, regOld, OE_Abort, 0);
if( aChange==0 || fkParentIsModified(pTab, pFKey, aChange, bChngRowid) ){
Trigger *pAct = fkActionTrigger(pParse, pTab, pFKey, pChanges);
if( pAct ){
sqlite3CodeRowTriggerDirect(pParse, pAct, pTab, regOld, OE_Abort, 0);
}
}
}
}
+7 -4
View File
@@ -1554,7 +1554,7 @@ static void setLikeOptFlag(sqlite3 *db, const char *zName, u8 flagVal){
pDef = sqlite3FindFunction(db, zName, sqlite3Strlen30(zName),
2, SQLITE_UTF8, 0);
if( ALWAYS(pDef) ){
pDef->flags = flagVal;
pDef->funcFlags |= flagVal;
}
}
@@ -1598,7 +1598,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
pDef = sqlite3FindFunction(db, pExpr->u.zToken,
sqlite3Strlen30(pExpr->u.zToken),
2, SQLITE_UTF8, 0);
if( NEVER(pDef==0) || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
if( NEVER(pDef==0) || (pDef->funcFlags & SQLITE_FUNC_LIKE)==0 ){
return 0;
}
@@ -1610,7 +1610,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
*pIsNocase = (pDef->funcFlags & SQLITE_FUNC_CASE)==0;
return 1;
}
@@ -1689,7 +1689,7 @@ void sqlite3RegisterGlobalFunctions(void){
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),
AGGREGATE(avg, 1, 0, 0, sumStep, avgFinalize ),
/* AGGREGATE(count, 0, 0, 0, countStep, countFinalize ), */
{0,SQLITE_UTF8,SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
{0,SQLITE_UTF8|SQLITE_FUNC_COUNT,0,0,0,countStep,countFinalize,"count",0,0},
AGGREGATE(count, 1, 0, 0, countStep, countFinalize ),
AGGREGATE(group_concat, 1, 0, 0, groupConcatStep, groupConcatFinalize),
AGGREGATE(group_concat, 2, 0, 0, groupConcatStep, groupConcatFinalize),
@@ -1715,4 +1715,7 @@ void sqlite3RegisterGlobalFunctions(void){
#ifndef SQLITE_OMIT_ALTERTABLE
sqlite3AlterFunctions();
#endif
#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4)
sqlite3AnalyzeFunctions();
#endif
}
+1 -1
View File
@@ -1031,7 +1031,7 @@ void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx,
keyColumn>=0, 0, onError, endOfLoop, &isReplace
);
sqlite3FkCheck(pParse, pTab, 0, regIns);
sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
sqlite3CompleteInsertion(
pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0
);
+4 -2
View File
@@ -1107,6 +1107,7 @@ const char *sqlite3ErrName(int rc){
case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break;
case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break;
case SQLITE_IOERR_CONVPATH: zName = "SQLITE_IOERR_CONVPATH"; break;
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
@@ -1115,6 +1116,7 @@ const char *sqlite3ErrName(int rc){
case SQLITE_CANTOPEN_NOTEMPDIR: zName = "SQLITE_CANTOPEN_NOTEMPDIR";break;
case SQLITE_CANTOPEN_ISDIR: zName = "SQLITE_CANTOPEN_ISDIR"; break;
case SQLITE_CANTOPEN_FULLPATH: zName = "SQLITE_CANTOPEN_FULLPATH"; break;
case SQLITE_CANTOPEN_CONVPATH: zName = "SQLITE_CANTOPEN_CONVPATH"; break;
case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break;
@@ -1404,7 +1406,7 @@ int sqlite3CreateFunc(
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0);
if( p && p->iPrefEnc==enc && p->nArg==nArg ){
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3Error(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
@@ -1429,7 +1431,7 @@ int sqlite3CreateFunc(
pDestructor->nRef++;
}
p->pDestructor = pDestructor;
p->flags = 0;
p->funcFlags &= SQLITE_FUNC_ENCMASK;
p->xFunc = xFunc;
p->xStep = xStep;
p->xFinalize = xFinal;
+8 -8
View File
@@ -179,7 +179,7 @@ static int sqlite3MemSize(void *p){
return 0;
}
pHdr = sqlite3MemsysGetHeader(p);
return pHdr->iSize;
return (int)pHdr->iSize;
}
/*
@@ -221,7 +221,7 @@ static void randomFill(char *pBuf, int nByte){
x = SQLITE_PTR_TO_INT(pBuf);
y = nByte | 1;
while( nByte >= 4 ){
x = (x>>1) ^ (-(x&1) & 0xd0000001);
x = (x>>1) ^ (-(int)(x&1) & 0xd0000001);
y = y*1103515245 + 12345;
r = x ^ y;
*(int*)pBuf = r;
@@ -229,7 +229,7 @@ static void randomFill(char *pBuf, int nByte){
nByte -= 4;
}
while( nByte-- > 0 ){
x = (x>>1) ^ (-(x&1) & 0xd0000001);
x = (x>>1) ^ (-(int)(x&1) & 0xd0000001);
y = y*1103515245 + 12345;
r = x ^ y;
*(pBuf++) = r & 0xff;
@@ -324,9 +324,9 @@ static void sqlite3MemFree(void *pPrior){
}
z = (char*)pBt;
z -= pHdr->nTitle;
adjustStats(pHdr->iSize, -1);
adjustStats((int)pHdr->iSize, -1);
randomFill(z, sizeof(void*)*pHdr->nBacktraceSlots + sizeof(*pHdr) +
pHdr->iSize + sizeof(int) + pHdr->nTitle);
(int)pHdr->iSize + sizeof(int) + pHdr->nTitle);
free(z);
sqlite3_mutex_leave(mem.mutex);
}
@@ -348,9 +348,9 @@ static void *sqlite3MemRealloc(void *pPrior, int nByte){
pOldHdr = sqlite3MemsysGetHeader(pPrior);
pNew = sqlite3MemMalloc(nByte);
if( pNew ){
memcpy(pNew, pPrior, nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize);
memcpy(pNew, pPrior, (int)(nByte<pOldHdr->iSize ? nByte : pOldHdr->iSize));
if( nByte>pOldHdr->iSize ){
randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - pOldHdr->iSize);
randomFill(&((char*)pNew)[pOldHdr->iSize], nByte - (int)pOldHdr->iSize);
}
sqlite3MemFree(pPrior);
}
@@ -465,7 +465,7 @@ void sqlite3MemdebugSync(){
for(pHdr=mem.pFirst; pHdr; pHdr=pHdr->pNext){
void **pBt = (void**)pHdr;
pBt -= pHdr->nBacktraceSlots;
mem.xBacktrace(pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
mem.xBacktrace((int)pHdr->iSize, pHdr->nBacktrace-1, &pBt[1]);
}
}
+2 -2
View File
@@ -69,7 +69,7 @@ struct sqlite3_mutex {
}
return osType==2;
}
#endif /* SQLITE_OS_WINCE */
#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */
#endif
#ifdef SQLITE_DEBUG
@@ -107,7 +107,7 @@ static int winMutex_isInit = 0;
** processing, the "interlocked" magic is probably not
** strictly necessary.
*/
static long winMutex_lock = 0;
static LONG winMutex_lock = 0;
void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
+46 -11
View File
@@ -218,11 +218,13 @@ struct unixFile {
const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
#if SQLITE_MAX_MMAP_SIZE>0
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
sqlite3_int64 mmapSizeActual; /* Actual size of mapping at pMapRegion */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#endif
#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
@@ -449,6 +451,7 @@ static struct unix_syscall {
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
@@ -461,6 +464,7 @@ static struct unix_syscall {
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
#endif
}; /* End of the overrideable system calls */
@@ -547,6 +551,15 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
return 0;
}
/*
** Do not accept any file descriptor less than this value, in order to avoid
** opening database file using file descriptors that are commonly used for
** standard input, output, and error.
*/
#ifndef SQLITE_MINIMUM_FILE_DESCRIPTOR
# define SQLITE_MINIMUM_FILE_DESCRIPTOR 3
#endif
/*
** Invoke open(). Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
@@ -567,13 +580,23 @@ static const char *unixNextSystemCall(sqlite3_vfs *p, const char *zName){
static int robust_open(const char *z, int f, mode_t m){
int fd;
mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
do{
while(1){
#if defined(O_CLOEXEC)
fd = osOpen(z,f|O_CLOEXEC,m2);
#else
fd = osOpen(z,f,m2);
#endif
}while( fd<0 && errno==EINTR );
if( fd<0 ){
if( errno==EINTR ) continue;
break;
}
if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break;
osClose(fd);
sqlite3_log(SQLITE_WARNING,
"attempt to open \"%s\" as file descriptor %d", z, fd);
fd = -1;
if( osOpen("/dev/null", f, m)<0 ) break;
}
if( fd>=0 ){
if( m!=0 ){
struct stat statbuf;
@@ -1871,8 +1894,10 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
return posixUnlock(id, eFileLock, 0);
}
#if SQLITE_MAX_MMAP_SIZE>0
static int unixMapfile(unixFile *pFd, i64 nByte);
static void unixUnmapfile(unixFile *pFd);
#endif
/*
** This function performs the parts of the "close file" operation
@@ -1886,7 +1911,9 @@ static void unixUnmapfile(unixFile *pFd);
*/
static int closeUnixFile(sqlite3_file *id){
unixFile *pFile = (unixFile*)id;
#if SQLITE_MAX_MMAP_SIZE>0
unixUnmapfile(pFile);
#endif
if( pFile->h>=0 ){
robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1;
@@ -3091,6 +3118,7 @@ static int seekAndRead(unixFile *id, sqlite3_int64 offset, void *pBuf, int cnt){
#endif
TIMER_START;
assert( cnt==(cnt&0x1ffff) );
assert( id->h>2 );
cnt &= 0x1ffff;
do{
#if defined(USE_PREAD)
@@ -3205,6 +3233,7 @@ static int seekAndWriteFd(
int rc = 0; /* Value returned by system call */
assert( nBuf==(nBuf&0x1ffff) );
assert( fd>2 );
nBuf &= 0x1ffff;
TIMER_START;
@@ -3590,6 +3619,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
}
#endif
#if SQLITE_MAX_MMAP_SIZE>0
/* If the file was just truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
@@ -3597,6 +3627,7 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
if( nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
}
#endif
return SQLITE_OK;
}
@@ -3686,6 +3717,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
}
}
#if SQLITE_MAX_MMAP_SIZE>0
if( pFile->mmapSizeMax>0 && nByte>pFile->mmapSize ){
int rc;
if( pFile->szChunk<=0 ){
@@ -3698,6 +3730,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
rc = unixMapfile(pFile, nByte);
return rc;
}
#endif
return SQLITE_OK;
}
@@ -3766,6 +3799,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
return SQLITE_OK;
}
#if SQLITE_MAX_MMAP_SIZE>0
case SQLITE_FCNTL_MMAP_SIZE: {
i64 newLimit = *(i64*)pArg;
int rc = SQLITE_OK;
@@ -3782,6 +3816,7 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
return rc;
}
#endif
#ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and
@@ -4592,22 +4627,20 @@ static int unixShmUnmap(
# define unixShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */
#if SQLITE_MAX_MMAP_SIZE>0
/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
assert( pFd->nFetchOut==0 );
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->pMapRegion ){
osMunmap(pFd->pMapRegion, pFd->mmapSizeActual);
pFd->pMapRegion = 0;
pFd->mmapSize = 0;
pFd->mmapSizeActual = 0;
}
#endif
}
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Return the system page size.
*/
@@ -4620,9 +4653,7 @@ static int unixGetPagesize(void){
return (int)sysconf(_SC_PAGESIZE);
#endif
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
@@ -4707,7 +4738,6 @@ static void unixRemapfile(
pFd->pMapRegion = (void *)pNew;
pFd->mmapSize = pFd->mmapSizeActual = nNew;
}
#endif
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
@@ -4726,7 +4756,6 @@ static void unixRemapfile(
** code otherwise.
*/
static int unixMapfile(unixFile *pFd, i64 nByte){
#if SQLITE_MAX_MMAP_SIZE>0
i64 nMap = nByte;
int rc;
@@ -4752,10 +4781,10 @@ static int unixMapfile(unixFile *pFd, i64 nByte){
unixUnmapfile(pFd);
}
}
#endif
return SQLITE_OK;
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
/*
** If possible, return a pointer to a mapping of file fd starting at offset
@@ -4804,6 +4833,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
UNUSED_PARAMETER(iOff);
#if SQLITE_MAX_MMAP_SIZE>0
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
@@ -4819,6 +4849,7 @@ static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
}
assert( pFd->nFetchOut>=0 );
#endif
return SQLITE_OK;
}
@@ -5150,7 +5181,9 @@ static int fillInUnixFile(
pNew->pVfs = pVfs;
pNew->zPath = zFilename;
pNew->ctrlFlags = (u8)ctrlFlags;
#if SQLITE_MAX_MMAP_SIZE>0
pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
#endif
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW;
@@ -5305,6 +5338,7 @@ static int fillInUnixFile(
*/
static const char *unixTempFileDir(void){
static const char *azDirs[] = {
0,
0,
0,
"/var/tmp",
@@ -5317,7 +5351,8 @@ static const char *unixTempFileDir(void){
const char *zDir = 0;
azDirs[0] = sqlite3_temp_directory;
if( !azDirs[1] ) azDirs[1] = getenv("TMPDIR");
if( !azDirs[1] ) azDirs[1] = getenv("SQLITE_TMPDIR");
if( !azDirs[2] ) azDirs[2] = getenv("TMPDIR");
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); zDir=azDirs[i++]){
if( zDir==0 ) continue;
if( osStat(zDir, &buf) ) continue;
+473 -225
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -1081,12 +1081,13 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, Z, 0);
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = Y;
A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
sqlite3ExprSetHeight(pParse, A.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, Y);
sqlite3ExprDelete(pParse->db, Z);
}
A.zStart = C.z;
A.zEnd = &E.z[E.n];
+5 -3
View File
@@ -661,7 +661,7 @@ void sqlite3Pragma(
Pager *pPager = sqlite3BtreePager(pDb->pBt);
i64 iLimit = -2;
if( zRight ){
sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
sqlite3Atoi64(zRight, &iLimit, sqlite3Strlen30(zRight), SQLITE_UTF8);
if( iLimit<-1 ) iLimit = -1;
}
iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
@@ -795,10 +795,11 @@ void sqlite3Pragma(
*/
if( sqlite3StrICmp(zLeft,"mmap_size")==0 ){
sqlite3_int64 sz;
#if SQLITE_MAX_MMAP_SIZE>0
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
sqlite3Atoi64(zRight, &sz, 1000, SQLITE_UTF8);
sqlite3Atoi64(zRight, &sz, sqlite3Strlen30(zRight), SQLITE_UTF8);
if( sz<0 ) sz = sqlite3GlobalConfig.szMmap;
if( pId2->n==0 ) db->szMmap = sz;
for(ii=db->nDb-1; ii>=0; ii--){
@@ -809,8 +810,9 @@ void sqlite3Pragma(
}
sz = -1;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_MMAP_SIZE, &sz);
#if SQLITE_MAX_MMAP_SIZE==0
#else
sz = 0;
rc = SQLITE_OK;
#endif
if( rc==SQLITE_OK ){
returnSingleInt(pParse, "mmap_size", sz);
+3 -3
View File
@@ -129,7 +129,7 @@ static void resolveAlias(
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
pExpr->flags2 |= EP2_MallocedToken;
pExpr->flags |= EP_MemToken;
}
sqlite3DbFree(db, pDup);
}
@@ -229,7 +229,7 @@ static int lookupName(
assert( pNC ); /* the name context cannot be NULL. */
assert( zCol ); /* The Z in X.Y.Z cannot be NULL */
assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pExpr, EP_TokenOnly|EP_Reduced) );
/* Initialize the node to no-match */
pExpr->iTable = -1;
@@ -591,7 +591,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pParse = pNC->pParse;
assert( pParse==pWalker->pParse );
if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return WRC_Prune;
if( ExprHasProperty(pExpr, EP_Resolved) ) return WRC_Prune;
ExprSetProperty(pExpr, EP_Resolved);
#ifndef NDEBUG
if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
+4 -4
View File
@@ -264,7 +264,7 @@ static void addWhereTerm(
pEq = sqlite3PExpr(pParse, TK_EQ, pE1, pE2, 0);
if( pEq && isOuterJoin ){
ExprSetProperty(pEq, EP_FromJoin);
assert( !ExprHasAnyProperty(pEq, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(pEq, EP_TokenOnly|EP_Reduced) );
ExprSetIrreducible(pEq);
pEq->iRightJoinTable = (i16)pE2->iTable;
}
@@ -300,7 +300,7 @@ static void addWhereTerm(
static void setJoinExpr(Expr *p, int iTable){
while( p ){
ExprSetProperty(p, EP_FromJoin);
assert( !ExprHasAnyProperty(p, EP_TokenOnly|EP_Reduced) );
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
ExprSetIrreducible(p);
p->iRightJoinTable = (i16)iTable;
setJoinExpr(p->pLeft, iTable);
@@ -3228,7 +3228,7 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){
if( IsVirtual(pTab) ) return 0;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( NEVER(pAggInfo->nFunc==0) ) return 0;
if( (pAggInfo->aFunc[0].pFunc->flags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( (pAggInfo->aFunc[0].pFunc->funcFlags&SQLITE_FUNC_COUNT)==0 ) return 0;
if( pExpr->flags&EP_Distinct ) return 0;
return pTab;
@@ -3825,7 +3825,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
assert( nArg==1 );
codeDistinct(pParse, pF->iDistinct, addrNext, 1, regAgg);
}
if( pF->pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
CollSeq *pColl = 0;
struct ExprList_item *pItem;
int j;
+12 -8
View File
@@ -71,12 +71,12 @@
/* Make sure isatty() has a prototype.
*/
extern int isatty(int);
#endif
/* popen and pclose are not C89 functions and so are sometimes omitted from
** the <stdio.h> header */
FILE *popen(const char*,const char*);
int pclose(FILE*);
extern FILE *popen(const char*,const char*);
extern int pclose(FILE*);
#endif
#if defined(_WIN32_WCE)
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
@@ -554,7 +554,7 @@ static void output_c_string(FILE *out, const char *z){
}else if( c=='\r' ){
fputc('\\', out);
fputc('r', out);
}else if( !isprint(c) ){
}else if( !isprint(c&0xff) ){
fprintf(out, "\\%03o", c&0xff);
}else{
fputc(c, out);
@@ -1194,7 +1194,7 @@ static int shell_exec(
char **azCols = (char **)pData; /* Names of result columns */
char **azVals = &azCols[nCol]; /* Results */
int *aiTypes = (int *)&azVals[nCol]; /* Result types */
int i;
int i, x;
assert(sizeof(int) <= sizeof(char *));
/* save off ptrs to column names */
for(i=0; i<nCol; i++){
@@ -1203,8 +1203,12 @@ static int shell_exec(
do{
/* extract the data and data types */
for(i=0; i<nCol; i++){
azVals[i] = (char *)sqlite3_column_text(pStmt, i);
aiTypes[i] = sqlite3_column_type(pStmt, i);
aiTypes[i] = x = sqlite3_column_type(pStmt, i);
if( x==SQLITE_BLOB && pArg->mode==MODE_Insert ){
azVals[i] = "";
}else{
azVals[i] = (char*)sqlite3_column_text(pStmt, i);
}
if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
rc = SQLITE_NOMEM;
break; /* from for */
@@ -1280,7 +1284,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
if( strcmp(zTable, "sqlite_sequence")==0 ){
zPrepStmt = "DELETE FROM sqlite_sequence;\n";
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
}else if( sqlite3_strglob("sqlite_stat?", zTable)==0 ){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
+2
View File
@@ -474,12 +474,14 @@ int sqlite3_exec(
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
+73 -66
View File
@@ -568,6 +568,20 @@ extern const int sqlite3one;
# define SQLITE_DEFAULT_MMAP_SIZE SQLITE_MAX_MMAP_SIZE
#endif
/*
** Only one of SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4 can be defined.
** Priority is given to SQLITE_ENABLE_STAT4. If either are defined, also
** define SQLITE_ENABLE_STAT3_OR_STAT4
*/
#ifdef SQLITE_ENABLE_STAT4
# undef SQLITE_ENABLE_STAT3
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
#elif SQLITE_ENABLE_STAT3
# define SQLITE_ENABLE_STAT3_OR_STAT4 1
#elif SQLITE_ENABLE_STAT3_OR_STAT4
# undef SQLITE_ENABLE_STAT3_OR_STAT4
#endif
/*
** An instance of the following structure is used to store the busy-handler
** callback for a given sqlite handle.
@@ -907,8 +921,6 @@ struct sqlite3 {
void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*);
void *pCollNeededArg;
sqlite3_value *pErr; /* Most recent error message */
char *zErrMsg; /* Most recent error message (UTF-8 encoded) */
char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */
union {
volatile int isInterrupted; /* True if sqlite3_interrupt has been called */
double notUsed1; /* Spacer */
@@ -1051,8 +1063,7 @@ struct sqlite3 {
*/
struct FuncDef {
i16 nArg; /* Number of arguments. -1 means unlimited */
u8 iPrefEnc; /* Preferred text encoding (SQLITE_UTF8, 16LE, 16BE) */
u8 flags; /* Some combination of SQLITE_FUNC_* */
u16 funcFlags; /* Some combination of SQLITE_FUNC_* */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); /* Regular function */
@@ -1088,14 +1099,16 @@ struct FuncDestructor {
** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
** are assert() statements in the code to verify this.
*/
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM 0x04 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x08 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_COUNT 0x10 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x20 /* Built-in coalesce() or ifnull() function */
#define SQLITE_FUNC_LENGTH 0x40 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x80 /* Built-in typeof() function */
#define SQLITE_FUNC_ENCMASK 0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE 0x004 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x008 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM 0x010 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */
#define SQLITE_FUNC_LENGTH 0x040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1123,18 +1136,18 @@ struct FuncDestructor {
** parameter.
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL), \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg, SQLITE_UTF8, (bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
{nArg, SQLITE_UTF8, bNC*SQLITE_FUNC_NEEDCOLL, \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_UTF8, flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
{nArg, SQLITE_UTF8|flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8, nc*SQLITE_FUNC_NEEDCOLL, \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
/*
@@ -1550,9 +1563,10 @@ struct Index {
unsigned autoIndex:2; /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
unsigned bUnordered:1; /* Use this index for == or IN queries only */
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nSample; /* Number of elements in aSample[] */
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
#endif
};
@@ -1563,16 +1577,11 @@ struct Index {
** analyze.c source file for additional information.
*/
struct IndexSample {
union {
char *z; /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
double r; /* Value if eType is SQLITE_FLOAT */
i64 i; /* Value if eType is SQLITE_INTEGER */
} u;
u8 eType; /* SQLITE_NULL, SQLITE_INTEGER ... etc. */
int nByte; /* Size in byte of text or blob. */
tRowcnt nEq; /* Est. number of rows where the key equals this sample */
tRowcnt nLt; /* Est. number of rows where key is less than this sample */
tRowcnt nDLt; /* Est. number of distinct keys less than this sample */
void *p; /* Pointer to sampled record */
int n; /* Size of record in bytes */
tRowcnt *anEq; /* Est. number of rows where the key equals this sample */
tRowcnt *anLt; /* Est. number of rows where key is less than this sample */
tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */
};
/*
@@ -1713,7 +1722,7 @@ typedef int ynVar;
struct Expr {
u8 op; /* Operation performed by this node */
char affinity; /* The affinity of the column or 0 if not a column */
u16 flags; /* Various flags. EP_* See below */
u32 flags; /* Various flags. EP_* See below */
union {
char *zToken; /* Token value. Zero terminated and dequoted */
int iValue; /* Non-negative integer value if EP_IntValue */
@@ -1727,8 +1736,8 @@ struct Expr {
Expr *pLeft; /* Left subnode */
Expr *pRight; /* Right subnode */
union {
ExprList *pList; /* Function arguments or in "<expr> IN (<expr-list)" */
Select *pSelect; /* Used for sub-selects and "<expr> IN (<select>)" */
ExprList *pList; /* op = IN, EXISTS, SELECT, CASE, FUNCTION, BETWEEN */
Select *pSelect; /* EP_xIsSelect and op = IN, EXISTS, SELECT */
} x;
/* If the EP_Reduced flag is set in the Expr.flags mask, then no
@@ -1746,7 +1755,6 @@ struct Expr {
** TK_VARIABLE: variable number (always >= 1). */
i16 iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
i16 iRightJoinTable; /* If EP_FromJoin, the right table of the join */
u8 flags2; /* Second set of flags. EP2_... */
u8 op2; /* TK_REGISTER: original value of Expr.op
** TK_COLUMN: the value of p5 for OP_Column
** TK_AGG_FUNCTION: nesting depth */
@@ -1757,28 +1765,24 @@ struct Expr {
/*
** The following are the meanings of bits in the Expr.flags field.
*/
#define EP_FromJoin 0x0001 /* Originated in ON or USING clause of a join */
#define EP_Agg 0x0002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x0004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x0008 /* Expression contains one or more errors */
#define EP_Distinct 0x0010 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x0020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x0040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x0080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x0100 /* Tree contains a TK_COLLATE opeartor */
#define EP_FixedDest 0x0200 /* Result needed in a specific register */
#define EP_IntValue 0x0400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x0800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Hint 0x1000 /* Not used */
#define EP_Reduced 0x2000 /* Expr struct is EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x4000 /* Expr struct is EXPR_TOKENONLYSIZE bytes only */
#define EP_Static 0x8000 /* Held in memory not obtained from malloc() */
/*
** The following are the meanings of bits in the Expr.flags2 field.
*/
#define EP2_MallocedToken 0x0001 /* Need to sqlite3DbFree() Expr.zToken */
#define EP2_Irreducible 0x0002 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
#define EP_Error 0x000008 /* Expression contains one or more errors */
#define EP_Distinct 0x000010 /* Aggregate function with DISTINCT keyword */
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
#define EP_FixedDest 0x000200 /* Result needed in a specific register */
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Hint 0x001000 /* Not used */
#define EP_Reduced 0x002000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
#define EP_Static 0x008000 /* Held in memory not obtained from malloc() */
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_Irreduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
/*
** The pseudo-routine sqlite3ExprSetIrreducible sets the EP2_Irreducible
@@ -1787,7 +1791,7 @@ struct Expr {
** so as not to burden production code.
*/
#ifdef SQLITE_DEBUG
# define ExprSetIrreducible(X) (X)->flags2 |= EP2_Irreducible
# define ExprSetIrreducible(X) (X)->flags |= EP_Irreduce
#else
# define ExprSetIrreducible(X)
#endif
@@ -1796,8 +1800,8 @@ struct Expr {
** These macros can be used to test, set, or clear bits in the
** Expr.flags field.
*/
#define ExprHasProperty(E,P) (((E)->flags&(P))==(P))
#define ExprHasAnyProperty(E,P) (((E)->flags&(P))!=0)
#define ExprHasProperty(E,P) (((E)->flags&(P))!=0)
#define ExprHasAllProperty(E,P) (((E)->flags&(P))==(P))
#define ExprSetProperty(E,P) (E)->flags|=(P)
#define ExprClearProperty(E,P) (E)->flags&=~(P)
@@ -3044,9 +3048,6 @@ void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void sqlite3ValueFree(sqlite3_value*);
sqlite3_value *sqlite3ValueNew(sqlite3 *);
char *sqlite3Utf16to8(sqlite3 *, const void*, int, u8);
#ifdef SQLITE_ENABLE_STAT3
char *sqlite3Utf8to16(sqlite3 *, u8, char *, int, int *);
#endif
int sqlite3ValueFromExpr(sqlite3 *, Expr *, u8, u8, sqlite3_value **);
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
#ifndef SQLITE_AMALGAMATION
@@ -3113,6 +3114,12 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int);
void sqlite3BackupRestart(sqlite3_backup *);
void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
void sqlite3AnalyzeFunctions(void);
int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*);
void sqlite3Stat4ProbeFree(UnpackedRecord*);
#endif
/*
** The interface to the LEMON-generated parser
*/
@@ -3196,18 +3203,18 @@ const char *sqlite3JournalModename(int);
** provided (enforcement of FK constraints requires the triggers sub-system).
*/
#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
void sqlite3FkCheck(Parse*, Table*, int, int);
void sqlite3FkCheck(Parse*, Table*, int, int, int*, int);
void sqlite3FkDropTable(Parse*, SrcList *, Table*);
void sqlite3FkActions(Parse*, Table*, ExprList*, int);
void sqlite3FkActions(Parse*, Table*, ExprList*, int, int*, int);
int sqlite3FkRequired(Parse*, Table*, int*, int);
u32 sqlite3FkOldmask(Parse*, Table*);
FKey *sqlite3FkReferences(Table *);
#else
#define sqlite3FkActions(a,b,c,d)
#define sqlite3FkActions(a,b,c,d,e,f)
#define sqlite3FkCheck(a,b,c,d)
#define sqlite3FkDropTable(a,b,c)
#define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c,d) 0
#define sqlite3FkOldmask(a,b) 0
#define sqlite3FkRequired(a,b,c,d,e,f) 0
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
void sqlite3FkDelete(sqlite3 *, Table*);
+144
View File
@@ -5934,6 +5934,145 @@ static int win32_file_lock(
CloseHandle(ev);
return TCL_OK;
}
/*
** exists_win32_path PATH
**
** Returns non-zero if the specified path exists, whose fully qualified name
** may exceed 260 characters if it is prefixed with "\\?\".
*/
static int win32_exists_path(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES ));
return TCL_OK;
}
/*
** find_win32_file PATTERN
**
** Returns a list of entries in a directory that match the specified pattern,
** whose fully qualified name may exceed 248 characters if it is prefixed with
** "\\?\".
*/
static int win32_find_file(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
HANDLE hFindFile = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW findData;
Tcl_Obj *listObj;
DWORD lastErrno;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "PATTERN");
return TCL_ERROR;
}
hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData);
if( hFindFile==INVALID_HANDLE_VALUE ){
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
return TCL_ERROR;
}
listObj = Tcl_NewObj();
Tcl_IncrRefCount(listObj);
do {
Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj(
findData.cFileName, -1));
Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(
findData.dwFileAttributes));
} while( FindNextFileW(hFindFile, &findData) );
lastErrno = GetLastError();
if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){
FindClose(hFindFile);
Tcl_DecrRefCount(listObj);
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
return TCL_ERROR;
}
FindClose(hFindFile);
Tcl_SetObjResult(interp, listObj);
return TCL_OK;
}
/*
** delete_win32_file FILENAME
**
** Deletes the specified file, whose fully qualified name may exceed 260
** characters if it is prefixed with "\\?\".
*/
static int win32_delete_file(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
return TCL_ERROR;
}
if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
return TCL_ERROR;
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/*
** make_win32_dir DIRECTORY
**
** Creates the specified directory, whose fully qualified name may exceed 248
** characters if it is prefixed with "\\?\".
*/
static int win32_mkdir(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
return TCL_ERROR;
}
if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
return TCL_ERROR;
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/*
** remove_win32_dir DIRECTORY
**
** Removes the specified directory, whose fully qualified name may exceed 248
** characters if it is prefixed with "\\?\".
*/
static int win32_rmdir(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
return TCL_ERROR;
}
if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
return TCL_ERROR;
}
Tcl_ResetResult(interp);
return TCL_OK;
}
#endif
@@ -6193,6 +6332,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "optimization_control", optimization_control,0},
#if SQLITE_OS_WIN
{ "lock_win32_file", win32_file_lock, 0 },
{ "exists_win32_path", win32_exists_path, 0 },
{ "find_win32_file", win32_find_file, 0 },
{ "delete_win32_file", win32_delete_file, 0 },
{ "make_win32_dir", win32_mkdir, 0 },
{ "remove_win32_dir", win32_rmdir, 0 },
#endif
{ "tcl_objproc", runAsObjProc, 0 },
+6 -1
View File
@@ -458,7 +458,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT4
Tcl_SetVar2(interp, "sqlite_options", "stat4", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "stat4", "0", TCL_GLOBAL_ONLY);
#endif
#if defined(SQLITE_ENABLE_STAT3) && !defined(SQLITE_ENABLE_STAT4)
Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "stat3", "0", TCL_GLOBAL_ONLY);
+146
View File
@@ -18,6 +18,9 @@
#include <string.h>
#include <assert.h>
#include "sqliteInt.h"
#include "vdbeInt.h"
/*
** Allocate nByte bytes of space using sqlite3_malloc(). If the
@@ -458,6 +461,147 @@ static void real2hex(
sqlite3_result_text(context, zOut, -1, SQLITE_TRANSIENT);
}
/*
** tclcmd: test_extract(record, field)
**
** This function implements an SQL user-function that accepts a blob
** containing a formatted database record as the first argument. The
** second argument is the index of the field within that record to
** extract and return.
*/
static void test_extract(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3 *db = sqlite3_context_db_handle(context);
u8 *pRec;
u8 *pEndHdr; /* Points to one byte past record header */
u8 *pHdr; /* Current point in record header */
u8 *pBody; /* Current point in record data */
u64 nHdr; /* Bytes in record header */
int iIdx; /* Required field */
int iCurrent = 0; /* Current field */
assert( argc==2 );
pRec = (u8*)sqlite3_value_blob(argv[0]);
iIdx = sqlite3_value_int(argv[1]);
pHdr = pRec + sqlite3GetVarint(pRec, &nHdr);
pBody = pEndHdr = &pRec[nHdr];
for(iCurrent=0; pHdr<pEndHdr && iCurrent<=iIdx; iCurrent++){
u64 iSerialType;
Mem mem;
memset(&mem, 0, sizeof(mem));
mem.db = db;
mem.enc = ENC(db);
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
sqlite3VdbeMemStoreType(&mem);
if( iCurrent==iIdx ){
sqlite3_result_value(context, &mem);
}
sqlite3DbFree(db, mem.zMalloc);
}
}
/*
** tclcmd: test_decode(record)
**
** This function implements an SQL user-function that accepts a blob
** containing a formatted database record as its only argument. It returns
** a tcl list (type SQLITE_TEXT) containing each of the values stored
** in the record.
*/
static void test_decode(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3 *db = sqlite3_context_db_handle(context);
u8 *pRec;
u8 *pEndHdr; /* Points to one byte past record header */
u8 *pHdr; /* Current point in record header */
u8 *pBody; /* Current point in record data */
u64 nHdr; /* Bytes in record header */
Tcl_Obj *pRet; /* Return value */
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
assert( argc==1 );
pRec = (u8*)sqlite3_value_blob(argv[0]);
pHdr = pRec + sqlite3GetVarint(pRec, &nHdr);
pBody = pEndHdr = &pRec[nHdr];
while( pHdr<pEndHdr ){
Tcl_Obj *pVal = 0;
u64 iSerialType;
Mem mem;
memset(&mem, 0, sizeof(mem));
mem.db = db;
mem.enc = ENC(db);
pHdr += sqlite3GetVarint(pHdr, &iSerialType);
pBody += sqlite3VdbeSerialGet(pBody, (u32)iSerialType, &mem);
sqlite3VdbeMemStoreType(&mem);
switch( sqlite3_value_type(&mem) ){
case SQLITE_TEXT:
pVal = Tcl_NewStringObj((const char*)sqlite3_value_text(&mem), -1);
break;
case SQLITE_BLOB: {
char hexdigit[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
int n = sqlite3_value_bytes(&mem);
u8 *z = (u8*)sqlite3_value_blob(&mem);
int i;
pVal = Tcl_NewStringObj("x'", -1);
for(i=0; i<n; i++){
char hex[3];
hex[0] = hexdigit[((z[i] >> 4) & 0x0F)];
hex[1] = hexdigit[(z[i] & 0x0F)];
hex[2] = '\0';
Tcl_AppendStringsToObj(pVal, hex, 0);
}
Tcl_AppendStringsToObj(pVal, "'", 0);
break;
}
case SQLITE_FLOAT:
pVal = Tcl_NewDoubleObj(sqlite3_value_double(&mem));
break;
case SQLITE_INTEGER:
pVal = Tcl_NewWideIntObj(sqlite3_value_int64(&mem));
break;
case SQLITE_NULL:
pVal = Tcl_NewStringObj("NULL", -1);
break;
default:
assert( 0 );
}
Tcl_ListObjAppendElement(0, pRet, pVal);
if( mem.zMalloc ){
sqlite3DbFree(db, mem.zMalloc);
}
}
sqlite3_result_text(context, Tcl_GetString(pRet), -1, SQLITE_TRANSIENT);
Tcl_DecrRefCount(pRet);
}
static int registerTestFunctions(sqlite3 *db){
static const struct {
@@ -482,6 +626,8 @@ static int registerTestFunctions(sqlite3 *db){
{ "test_isolation", 2, SQLITE_UTF8, test_isolation},
{ "test_counter", 1, SQLITE_UTF8, counterFunc},
{ "real2hex", 1, SQLITE_UTF8, real2hex},
{ "test_decode", 1, SQLITE_UTF8, test_decode},
{ "test_extract", 2, SQLITE_UTF8, test_extract},
};
int i;
+1 -1
View File
@@ -749,7 +749,7 @@ static void test_memdebug_callback(int nByte, int nFrame, void **aFrame){
int isNew;
int aKey[MALLOC_LOG_KEYINTS];
int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
unsigned int nKey = sizeof(int)*MALLOC_LOG_KEYINTS;
memset(aKey, 0, nKey);
if( (sizeof(void*)*nFrame)<nKey ){
+4 -4
View File
@@ -61,7 +61,7 @@ static void updateVirtualTable(
void sqlite3ColumnDefault(Vdbe *v, Table *pTab, int i, int iReg){
assert( pTab!=0 );
if( !pTab->pSelect ){
sqlite3_value *pValue;
sqlite3_value *pValue = 0;
u8 enc = ENC(sqlite3VdbeDb(v));
Column *pCol = &pTab->aCol[i];
VdbeComment((v, "%s.%s", pTab->zName, pCol->zName));
@@ -488,7 +488,7 @@ void sqlite3Update(
/* Do FK constraint checks. */
if( hasFK ){
sqlite3FkCheck(pParse, pTab, regOldRowid, 0);
sqlite3FkCheck(pParse, pTab, regOldRowid, 0, aXRef, chngRowid);
}
/* Delete the index entries associated with the current record. */
@@ -502,7 +502,7 @@ void sqlite3Update(
sqlite3VdbeJumpHere(v, j1);
if( hasFK ){
sqlite3FkCheck(pParse, pTab, 0, regNewRowid);
sqlite3FkCheck(pParse, pTab, 0, regNewRowid, aXRef, chngRowid);
}
/* Insert the new index entries and the new record. */
@@ -512,7 +512,7 @@ void sqlite3Update(
** handle rows (possibly in other tables) that refer via a foreign key
** to the row just updated. */
if( hasFK ){
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid);
sqlite3FkActions(pParse, pTab, pChanges, regOldRowid, aXRef, chngRowid);
}
}
-26
View File
@@ -450,32 +450,6 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
return m.z;
}
/*
** Convert a UTF-8 string to the UTF-16 encoding specified by parameter
** enc. A pointer to the new string is returned, and the value of *pnOut
** is set to the length of the returned string in bytes. The call should
** arrange to call sqlite3DbFree() on the returned pointer when it is
** no longer required.
**
** If a malloc failure occurs, NULL is returned and the db.mallocFailed
** flag set.
*/
#ifdef SQLITE_ENABLE_STAT3
char *sqlite3Utf8to16(sqlite3 *db, u8 enc, char *z, int n, int *pnOut){
Mem m;
memset(&m, 0, sizeof(m));
m.db = db;
sqlite3VdbeMemSetStr(&m, z, n, SQLITE_UTF8, SQLITE_STATIC);
if( sqlite3VdbeMemTranslate(&m, enc) ){
assert( db->mallocFailed );
return 0;
}
assert( m.z==m.zMalloc );
*pnOut = m.n;
return m.z;
}
#endif
/*
** zIn is a UTF-16 encoded unicode string at least nChar characters long.
** Return the number of bytes in the first nChar unicode characters
+32 -31
View File
@@ -638,7 +638,7 @@ int sqlite3VdbeExec(
assert( pOp->opflags==sqlite3OpcodeProperty[pOp->opcode] );
if( pOp->opflags & OPFLG_OUT2_PRERELEASE ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
assert( pOp->p2<=(p->nMem-p->nCursor) );
pOut = &aMem[pOp->p2];
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
@@ -649,30 +649,30 @@ int sqlite3VdbeExec(
#ifdef SQLITE_DEBUG
if( (pOp->opflags & OPFLG_IN1)!=0 ){
assert( pOp->p1>0 );
assert( pOp->p1<=p->nMem );
assert( pOp->p1<=(p->nMem-p->nCursor) );
assert( memIsValid(&aMem[pOp->p1]) );
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
}
if( (pOp->opflags & OPFLG_IN2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
assert( pOp->p2<=(p->nMem-p->nCursor) );
assert( memIsValid(&aMem[pOp->p2]) );
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_IN3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
assert( pOp->p3<=(p->nMem-p->nCursor) );
assert( memIsValid(&aMem[pOp->p3]) );
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
}
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
assert( pOp->p2<=(p->nMem-p->nCursor) );
memAboutToChange(p, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
assert( pOp->p3<=(p->nMem-p->nCursor) );
memAboutToChange(p, &aMem[pOp->p3]);
}
#endif
@@ -765,7 +765,7 @@ check_for_interrupt:
** and then jump to address P2.
*/
case OP_Gosub: { /* jump */
assert( pOp->p1>0 && pOp->p1<=p->nMem );
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
memAboutToChange(p, pIn1);
@@ -977,7 +977,7 @@ case OP_Null: { /* out2-prerelease */
int cnt;
u16 nullFlag;
cnt = pOp->p3-pOp->p2;
assert( pOp->p3<=p->nMem );
assert( pOp->p3<=(p->nMem-p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
while( cnt>0 ){
pOut++;
@@ -1046,8 +1046,8 @@ case OP_Move: {
pIn1 = &aMem[p1];
pOut = &aMem[p2];
while( n-- ){
assert( pOut<=&aMem[p->nMem] );
assert( pIn1<=&aMem[p->nMem] );
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
zMalloc = pOut->zMalloc;
@@ -1131,7 +1131,7 @@ case OP_ResultRow: {
int i;
assert( p->nResColumn==pOp->p2 );
assert( pOp->p1>0 );
assert( pOp->p1+pOp->p2<=p->nMem+1 );
assert( pOp->p1+pOp->p2<=(p->nMem-p->nCursor)+1 );
/* If this statement has violated immediate foreign key constraints, do
** not return the number of rows modified. And do not RELEASE the statement
@@ -1405,11 +1405,11 @@ case OP_Function: {
n = pOp->p5;
apVal = p->apArg;
assert( apVal || n==0 );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut = &aMem[pOp->p3];
memAboutToChange(p, pOut);
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=(p->nMem-p->nCursor)+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
@@ -1437,7 +1437,7 @@ case OP_Function: {
MemSetTypeFlag(&ctx.s, MEM_Null);
ctx.fErrorOrAux = 0;
if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
@@ -1939,11 +1939,11 @@ case OP_Compare: {
if( aPermute ){
int k, mx = 0;
for(k=0; k<n; k++) if( aPermute[k]>mx ) mx = aPermute[k];
assert( p1>0 && p1+mx<=p->nMem+1 );
assert( p2>0 && p2+mx<=p->nMem+1 );
assert( p1>0 && p1+mx<=(p->nMem-p->nCursor)+1 );
assert( p2>0 && p2+mx<=(p->nMem-p->nCursor)+1 );
}else{
assert( p1>0 && p1+n<=p->nMem+1 );
assert( p2>0 && p2+n<=p->nMem+1 );
assert( p1>0 && p1+n<=(p->nMem-p->nCursor)+1 );
assert( p2>0 && p2+n<=(p->nMem-p->nCursor)+1 );
}
#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
@@ -2194,7 +2194,7 @@ case OP_Column: {
pC = 0;
memset(&sMem, 0, sizeof(sMem));
assert( p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
zRec = 0;
@@ -2492,7 +2492,7 @@ case OP_Affinity: {
assert( zAffinity[pOp->p2]==0 );
pIn1 = &aMem[pOp->p1];
while( (cAff = *(zAffinity++))!=0 ){
assert( pIn1 <= &p->aMem[p->nMem] );
assert( pIn1 <= &p->aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
ExpandBlob(pIn1);
applyAffinity(pIn1, cAff, encoding);
@@ -2553,7 +2553,7 @@ case OP_MakeRecord: {
nZero = 0; /* Number of zero bytes at the end of the record */
nField = pOp->p1;
zAffinity = pOp->p4.z;
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem+1 );
assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=(p->nMem-p->nCursor)+1 );
pData0 = &aMem[nField];
nField = pOp->p2;
pLast = &pData0[nField-1];
@@ -2619,7 +2619,7 @@ case OP_MakeRecord: {
}
assert( i==nByte );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut->n = (int)nByte;
pOut->flags = MEM_Blob | MEM_Dyn;
pOut->xDel = 0;
@@ -3199,7 +3199,7 @@ case OP_OpenWrite: {
}
if( pOp->p5 & OPFLAG_P2ISREG ){
assert( p2>0 );
assert( p2<=p->nMem );
assert( p2<=(p->nMem-p->nCursor) );
pIn2 = &aMem[p2];
assert( memIsValid(pIn2) );
assert( (pIn2->flags & MEM_Int)!=0 );
@@ -3736,7 +3736,7 @@ case OP_IsUnique: { /* jump, in3 */
aMx = &aMem[pOp->p4.i];
/* Assert that the values of parameters P1 and P4 are in range. */
assert( pOp->p4type==P4_INT32 );
assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem );
assert( pOp->p4.i>0 && pOp->p4.i<=(p->nMem-p->nCursor) );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
/* Find the index cursor. */
@@ -3939,7 +3939,7 @@ case OP_NewRowid: { /* out2-prerelease */
pMem = &pFrame->aMem[pOp->p3];
}else{
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
assert( pOp->p3<=(p->nMem-p->nCursor) );
pMem = &aMem[pOp->p3];
memAboutToChange(p, pMem);
}
@@ -4593,7 +4593,7 @@ case OP_IdxDelete: {
UnpackedRecord r;
assert( pOp->p3>0 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=p->nMem+1 );
assert( pOp->p2>0 && pOp->p2+pOp->p3<=(p->nMem-p->nCursor)+1 );
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
@@ -4801,6 +4801,7 @@ case OP_Clear: {
nChange = 0;
assert( p->readOnly==0 );
assert( pOp->p1!=1 );
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
rc = sqlite3BtreeClearTable(
db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
@@ -5001,7 +5002,7 @@ case OP_IntegrityCk: {
assert( nRoot>0 );
aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
if( aRoot==0 ) goto no_mem;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pnErr = &aMem[pOp->p3];
assert( (pnErr->flags & MEM_Int)!=0 );
assert( (pnErr->flags & (MEM_Str|MEM_Blob))==0 );
@@ -5425,7 +5426,7 @@ case OP_AggStep: {
sqlite3VdbeMemStoreType(pRec);
}
ctx.pFunc = pOp->p4.pFunc;
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
ctx.pMem = pMem = &aMem[pOp->p3];
pMem->n++;
ctx.s.flags = MEM_Null;
@@ -5436,7 +5437,7 @@ case OP_AggStep: {
ctx.isError = 0;
ctx.pColl = 0;
ctx.skipFlag = 0;
if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>p->aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
@@ -5472,7 +5473,7 @@ case OP_AggStep: {
*/
case OP_AggFinal: {
Mem *pMem;
assert( pOp->p1>0 && pOp->p1<=p->nMem );
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pMem = &aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
@@ -5889,7 +5890,7 @@ case OP_VColumn: {
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
if( pCur->nullRow ){
+1 -1
View File
@@ -604,7 +604,7 @@ void sqlite3VdbeJumpHere(Vdbe *p, int addr){
** the FuncDef is not ephermal, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
if( ALWAYS(pDef) && (pDef->flags & SQLITE_FUNC_EPHEM)!=0 ){
if( ALWAYS(pDef) && (pDef->funcFlags & SQLITE_FUNC_EPHEM)!=0 ){
sqlite3DbFree(db, pDef);
}
}
+279 -25
View File
@@ -1001,27 +1001,92 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){
}
/*
** Create a new sqlite3_value object, containing the value of pExpr.
**
** This only works for very simple expressions that consist of one constant
** token (i.e. "5", "5.1", "'a string'"). If the expression can
** be converted directly into a value, then the value is allocated and
** a pointer written to *ppVal. The caller is responsible for deallocating
** the value by passing it to sqlite3ValueFree() later on. If the expression
** cannot be converted to a value, then *ppVal is set to NULL.
** Context object passed by sqlite3Stat4ProbeSetValue() through to
** valueNew(). See comments above valueNew() for details.
*/
int sqlite3ValueFromExpr(
sqlite3 *db, /* The database connection */
Expr *pExpr, /* The expression to evaluate */
u8 enc, /* Encoding to use */
u8 affinity, /* Affinity to use */
sqlite3_value **ppVal /* Write the new value here */
struct ValueNewStat4Ctx {
Parse *pParse;
Index *pIdx;
UnpackedRecord **ppRec;
int iVal;
};
/*
** Allocate and return a pointer to a new sqlite3_value object. If
** the second argument to this function is NULL, the object is allocated
** by calling sqlite3ValueNew().
**
** Otherwise, if the second argument is non-zero, then this function is
** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not
** already been allocated, allocate the UnpackedRecord structure that
** that function will return to its caller here. Then return a pointer
** an sqlite3_value within the UnpackedRecord.a[] array.
*/
static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( p ){
UnpackedRecord *pRec = p->ppRec[0];
if( pRec==0 ){
Index *pIdx = p->pIdx; /* Index being probed */
int nByte; /* Bytes of space to allocate */
int i; /* Counter variable */
int nCol = pIdx->nColumn+1; /* Number of index columns including rowid */
nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord);
pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
if( pRec ){
pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx);
if( pRec->pKeyInfo ){
assert( pRec->pKeyInfo->nField+1==nCol );
pRec->pKeyInfo->enc = ENC(db);
pRec->flags = UNPACKED_PREFIX_MATCH;
pRec->aMem = (Mem *)&pRec[1];
for(i=0; i<nCol; i++){
pRec->aMem[i].flags = MEM_Null;
pRec->aMem[i].type = SQLITE_NULL;
pRec->aMem[i].db = db;
}
}else{
sqlite3DbFree(db, pRec);
pRec = 0;
}
}
if( pRec==0 ) return 0;
p->ppRec[0] = pRec;
}
pRec->nField = p->iVal+1;
return &pRec->aMem[p->iVal];
}
#endif
return sqlite3ValueNew(db);
}
/*
** Extract a value from the supplied expression in the manner described
** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object
** using valueNew().
**
** If pCtx is NULL and an error occurs after the sqlite3_value object
** has been allocated, it is freed before returning. Or, if pCtx is not
** NULL, it is assumed that the caller will free any allocated object
** in all cases.
*/
int valueFromExpr(
sqlite3 *db, /* The database connection */
Expr *pExpr, /* The expression to evaluate */
u8 enc, /* Encoding to use */
u8 affinity, /* Affinity to use */
sqlite3_value **ppVal, /* Write the new value here */
struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */
){
int op;
char *zVal = 0;
sqlite3_value *pVal = 0;
int negInt = 1;
const char *zNeg = "";
int rc = SQLITE_OK;
if( !pExpr ){
*ppVal = 0;
@@ -1029,11 +1094,11 @@ int sqlite3ValueFromExpr(
}
op = pExpr->op;
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT3.
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT4.
** The ifdef here is to enable us to achieve 100% branch test coverage even
** when SQLITE_ENABLE_STAT3 is omitted.
** when SQLITE_ENABLE_STAT4 is omitted.
*/
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( op==TK_REGISTER ) op = pExpr->op2;
#else
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
@@ -1051,7 +1116,7 @@ int sqlite3ValueFromExpr(
}
if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
pVal = sqlite3ValueNew(db);
pVal = valueNew(db, pCtx);
if( pVal==0 ) goto no_mem;
if( ExprHasProperty(pExpr, EP_IntValue) ){
sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
@@ -1068,11 +1133,13 @@ int sqlite3ValueFromExpr(
}
if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
if( enc!=SQLITE_UTF8 ){
sqlite3VdbeChangeEncoding(pVal, enc);
rc = sqlite3VdbeChangeEncoding(pVal, enc);
}
}else if( op==TK_UMINUS ) {
/* This branch happens for multiple negative signs. Ex: -(-5) */
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal)
&& pVal!=0
){
sqlite3VdbeMemNumerify(pVal);
if( pVal->u.i==SMALLEST_INT64 ){
pVal->flags &= MEM_Int;
@@ -1085,7 +1152,7 @@ int sqlite3ValueFromExpr(
sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}else if( op==TK_NULL ){
pVal = sqlite3ValueNew(db);
pVal = valueNew(db, pCtx);
if( pVal==0 ) goto no_mem;
}
#ifndef SQLITE_OMIT_BLOB_LITERAL
@@ -1093,7 +1160,7 @@ int sqlite3ValueFromExpr(
int nVal;
assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
assert( pExpr->u.zToken[1]=='\'' );
pVal = sqlite3ValueNew(db);
pVal = valueNew(db, pCtx);
if( !pVal ) goto no_mem;
zVal = &pExpr->u.zToken[2];
nVal = sqlite3Strlen30(zVal)-1;
@@ -1107,16 +1174,203 @@ int sqlite3ValueFromExpr(
sqlite3VdbeMemStoreType(pVal);
}
*ppVal = pVal;
return SQLITE_OK;
return rc;
no_mem:
db->mallocFailed = 1;
sqlite3DbFree(db, zVal);
sqlite3ValueFree(pVal);
*ppVal = 0;
assert( *ppVal==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( pCtx==0 ) sqlite3ValueFree(pVal);
#else
assert( pCtx==0 ); sqlite3ValueFree(pVal);
#endif
return SQLITE_NOMEM;
}
/*
** Create a new sqlite3_value object, containing the value of pExpr.
**
** This only works for very simple expressions that consist of one constant
** token (i.e. "5", "5.1", "'a string'"). If the expression can
** be converted directly into a value, then the value is allocated and
** a pointer written to *ppVal. The caller is responsible for deallocating
** the value by passing it to sqlite3ValueFree() later on. If the expression
** cannot be converted to a value, then *ppVal is set to NULL.
*/
int sqlite3ValueFromExpr(
sqlite3 *db, /* The database connection */
Expr *pExpr, /* The expression to evaluate */
u8 enc, /* Encoding to use */
u8 affinity, /* Affinity to use */
sqlite3_value **ppVal /* Write the new value here */
){
return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0);
}
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** The implementation of the sqlite_record() function. This function accepts
** a single argument of any type. The return value is a formatted database
** record (a blob) containing the argument value.
**
** This is used to convert the value stored in the 'sample' column of the
** sqlite_stat3 table to the record format SQLite uses internally.
*/
static void recordFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const int file_format = 1;
int iSerial; /* Serial type */
int nSerial; /* Bytes of space for iSerial as varint */
int nVal; /* Bytes of space required for argv[0] */
int nRet;
sqlite3 *db;
u8 *aRet;
iSerial = sqlite3VdbeSerialType(argv[0], file_format);
nSerial = sqlite3VarintLen(iSerial);
nVal = sqlite3VdbeSerialTypeLen(iSerial);
db = sqlite3_context_db_handle(context);
nRet = 1 + nSerial + nVal;
aRet = sqlite3DbMallocRaw(db, nRet);
if( aRet==0 ){
sqlite3_result_error_nomem(context);
}else{
aRet[0] = nSerial+1;
sqlite3PutVarint(&aRet[1], iSerial);
sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format);
sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT);
sqlite3DbFree(db, aRet);
}
}
/*
** Register built-in functions used to help read ANALYZE data.
*/
void sqlite3AnalyzeFunctions(void){
static SQLITE_WSD FuncDef aAnalyzeTableFuncs[] = {
FUNCTION(sqlite_record, 1, 0, 0, recordFunc),
};
int i;
FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
FuncDef *aFunc = (FuncDef*)&GLOBAL(FuncDef, aAnalyzeTableFuncs);
for(i=0; i<ArraySize(aAnalyzeTableFuncs); i++){
sqlite3FuncDefInsert(pHash, &aFunc[i]);
}
}
/*
** This function is used to allocate and populate UnpackedRecord
** structures intended to be compared against sample index keys stored
** in the sqlite_stat4 table.
**
** A single call to this function attempts to populates field iVal (leftmost
** is 0 etc.) of the unpacked record with a value extracted from expression
** pExpr. Extraction of values is possible if:
**
** * (pExpr==0). In this case the value is assumed to be an SQL NULL,
**
** * The expression is a bound variable, and this is a reprepare, or
**
** * The sqlite3ValueFromExpr() function is able to extract a value
** from the expression (i.e. the expression is a literal value).
**
** If a value can be extracted, the affinity passed as the 5th argument
** is applied to it before it is copied into the UnpackedRecord. Output
** parameter *pbOk is set to true if a value is extracted, or false
** otherwise.
**
** When this function is called, *ppRec must either point to an object
** allocated by an earlier call to this function, or must be NULL. If it
** is NULL and a value can be successfully extracted, a new UnpackedRecord
** is allocated (and *ppRec set to point to it) before returning.
**
** Unless an error is encountered, SQLITE_OK is returned. It is not an
** error if a value cannot be extracted from pExpr. If an error does
** occur, an SQLite error code is returned.
*/
int sqlite3Stat4ProbeSetValue(
Parse *pParse, /* Parse context */
Index *pIdx, /* Index being probed */
UnpackedRecord **ppRec, /* IN/OUT: Probe record */
Expr *pExpr, /* The expression to extract a value from */
u8 affinity, /* Affinity to use */
int iVal, /* Array element to populate */
int *pbOk /* OUT: True if value was extracted */
){
int rc = SQLITE_OK;
sqlite3_value *pVal = 0;
sqlite3 *db = pParse->db;
struct ValueNewStat4Ctx alloc;
alloc.pParse = pParse;
alloc.pIdx = pIdx;
alloc.ppRec = ppRec;
alloc.iVal = iVal;
/* Skip over any TK_COLLATE nodes */
pExpr = sqlite3ExprSkipCollate(pExpr);
if( !pExpr ){
pVal = valueNew(db, &alloc);
if( pVal ){
sqlite3VdbeMemSetNull((Mem*)pVal);
*pbOk = 1;
}
}else if( pExpr->op==TK_VARIABLE
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
){
Vdbe *v;
int iBindVar = pExpr->iColumn;
sqlite3VdbeSetVarmask(pParse->pVdbe, iBindVar);
if( (v = pParse->pReprepare)!=0 ){
pVal = valueNew(db, &alloc);
if( pVal ){
rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iBindVar-1]);
if( rc==SQLITE_OK ){
sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
}
pVal->db = pParse->db;
*pbOk = 1;
sqlite3VdbeMemStoreType((Mem*)pVal);
}
}else{
*pbOk = 0;
}
}else{
rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc);
*pbOk = (pVal!=0);
}
assert( pVal==0 || pVal->db==db );
return rc;
}
/*
** Unless it is NULL, the argument must be an UnpackedRecord object returned
** by an earlier call to sqlite3Stat4ProbeSetValue(). This call deletes
** the object.
*/
void sqlite3Stat4ProbeFree(UnpackedRecord *pRec){
if( pRec ){
int i;
int nCol = pRec->pKeyInfo->nField+1;
Mem *aMem = pRec->aMem;
sqlite3 *db = aMem[0].db;
for(i=0; i<nCol; i++){
sqlite3DbFree(db, aMem[i].zMalloc);
}
sqlite3DbFree(db, pRec->pKeyInfo);
sqlite3DbFree(db, pRec);
}
}
#endif /* ifdef SQLITE_ENABLE_STAT4 */
/*
** Change the string value of an sqlite3_value object
*/
+1 -1
View File
@@ -1013,7 +1013,7 @@ FuncDef *sqlite3VtabOverloadFunction(
memcpy(pNew->zName, pDef->zName, sqlite3Strlen30(pDef->zName)+1);
pNew->xFunc = xFunc;
pNew->pUserData = pArg;
pNew->flags |= SQLITE_FUNC_EPHEM;
pNew->funcFlags |= SQLITE_FUNC_EPHEM;
return pNew;
}
+1 -1
View File
@@ -43,7 +43,7 @@ int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
testcase( ExprHasProperty(pExpr, EP_Reduced) );
rc = pWalker->xExprCallback(pWalker, pExpr);
if( rc==WRC_Continue
&& !ExprHasAnyProperty(pExpr,EP_TokenOnly) ){
&& !ExprHasProperty(pExpr,EP_TokenOnly) ){
if( sqlite3WalkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
if( sqlite3WalkExpr(pWalker, pExpr->pRight) ) return WRC_Abort;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
+257 -255
View File
@@ -106,6 +106,7 @@ struct WhereLevel {
Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */
} u;
struct WhereLoop *pWLoop; /* The selected WhereLoop object */
Bitmask notReady; /* FROM entries not usable at this level */
};
/*
@@ -185,9 +186,9 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int);
** that implement some or all of a query plan.
**
** Think of each WhereLoop object as a node in a graph with arcs
** showing dependences and costs for travelling between nodes. (That is
** showing dependencies and costs for travelling between nodes. (That is
** not a completely accurate description because WhereLoop costs are a
** vector, not a scalar, and because dependences are many-to-one, not
** vector, not a scalar, and because dependencies are many-to-one, not
** one-to-one as are graph nodes. But it is a useful visualization aid.)
** Then a WherePath object is a path through the graph that visits some
** or all of the WhereLoop objects once.
@@ -286,7 +287,7 @@ struct WhereTerm {
#define TERM_ORINFO 0x10 /* Need to free the WhereTerm.u.pOrInfo object */
#define TERM_ANDINFO 0x20 /* Need to free the WhereTerm.u.pAndInfo obj */
#define TERM_OR_OK 0x40 /* Used during OR-clause processing */
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
# define TERM_VNULL 0x80 /* Manufactured x>NULL or x<=NULL term */
#else
# define TERM_VNULL 0x00 /* Disabled if not using stat3 */
@@ -392,6 +393,10 @@ struct WhereLoopBuilder {
ExprList *pOrderBy; /* ORDER BY clause */
WhereLoop *pNew; /* Template WhereLoop */
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
UnpackedRecord *pRec; /* Probe for stat4 (if required) */
int nRecValid; /* Number of valid fields currently in pRec */
#endif
};
/*
@@ -1791,7 +1796,7 @@ static void exprAnalyze(
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/* When sqlite_stat3 histogram data is available an operator of the
** form "x IS NOT NULL" can sometimes be evaluated more efficiently
** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a
@@ -1831,7 +1836,7 @@ static void exprAnalyze(
pNewTerm->prereqAll = pTerm->prereqAll;
}
}
#endif /* SQLITE_ENABLE_STAT */
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/* Prevent ON clause terms of a LEFT JOIN from being used to drive
** an index for tables to the left of the join.
@@ -2399,7 +2404,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Estimate the location of a particular key among all keys in an
** index. Store the results in aStat as follows:
@@ -2409,141 +2414,73 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
**
** Return SQLITE_OK on success.
*/
static int whereKeyStats(
static void whereKeyStats(
Parse *pParse, /* Database connection */
Index *pIdx, /* Index to consider domain of */
sqlite3_value *pVal, /* Value to consider */
UnpackedRecord *pRec, /* Vector of values to consider */
int roundUp, /* Round up if true. Round down if false */
tRowcnt *aStat /* OUT: stats written here */
){
tRowcnt n;
IndexSample *aSample;
int i, eType;
int isEq = 0;
i64 v;
double r, rS;
IndexSample *aSample = pIdx->aSample;
int iCol; /* Index of required stats in anEq[] etc. */
int iMin = 0; /* Smallest sample not yet tested */
int i = pIdx->nSample; /* Smallest sample larger than or equal to pRec */
int iTest; /* Next sample to test */
int res; /* Result of comparison operation */
assert( roundUp==0 || roundUp==1 );
assert( pRec!=0 || pParse->db->mallocFailed );
if( pRec==0 ) return;
iCol = pRec->nField - 1;
assert( pIdx->nSample>0 );
if( pVal==0 ) return SQLITE_ERROR;
n = pIdx->aiRowEst[0];
aSample = pIdx->aSample;
eType = sqlite3_value_type(pVal);
assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
do{
iTest = (iMin+i)/2;
res = sqlite3VdbeRecordCompare(aSample[iTest].n, aSample[iTest].p, pRec);
if( res<0 ){
iMin = iTest+1;
}else{
i = iTest;
}
}while( res && iMin<i );
if( eType==SQLITE_INTEGER ){
v = sqlite3_value_int64(pVal);
r = (i64)v;
for(i=0; i<pIdx->nSample; i++){
if( aSample[i].eType==SQLITE_NULL ) continue;
if( aSample[i].eType>=SQLITE_TEXT ) break;
if( aSample[i].eType==SQLITE_INTEGER ){
if( aSample[i].u.i>=v ){
isEq = aSample[i].u.i==v;
break;
}
}else{
assert( aSample[i].eType==SQLITE_FLOAT );
if( aSample[i].u.r>=r ){
isEq = aSample[i].u.r==r;
break;
}
}
}
}else if( eType==SQLITE_FLOAT ){
r = sqlite3_value_double(pVal);
for(i=0; i<pIdx->nSample; i++){
if( aSample[i].eType==SQLITE_NULL ) continue;
if( aSample[i].eType>=SQLITE_TEXT ) break;
if( aSample[i].eType==SQLITE_FLOAT ){
rS = aSample[i].u.r;
}else{
rS = aSample[i].u.i;
}
if( rS>=r ){
isEq = rS==r;
break;
}
}
}else if( eType==SQLITE_NULL ){
i = 0;
if( aSample[0].eType==SQLITE_NULL ) isEq = 1;
#ifdef SQLITE_DEBUG
/* The following assert statements check that the binary search code
** above found the right answer. This block serves no purpose other
** than to invoke the asserts. */
if( res==0 ){
/* If (res==0) is true, then sample $i must be equal to pRec */
assert( i<pIdx->nSample );
assert( 0==sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)
|| pParse->db->mallocFailed );
}else{
assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
for(i=0; i<pIdx->nSample; i++){
if( aSample[i].eType==SQLITE_TEXT || aSample[i].eType==SQLITE_BLOB ){
break;
}
}
if( i<pIdx->nSample ){
sqlite3 *db = pParse->db;
CollSeq *pColl;
const u8 *z;
if( eType==SQLITE_BLOB ){
z = (const u8 *)sqlite3_value_blob(pVal);
pColl = db->pDfltColl;
assert( pColl->enc==SQLITE_UTF8 );
}else{
pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
/* If the collating sequence was unavailable, we should have failed
** long ago and never reached this point. But we'll check just to
** be doubly sure. */
if( NEVER(pColl==0) ) return SQLITE_ERROR;
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
if( !z ){
return SQLITE_NOMEM;
}
assert( z && pColl && pColl->xCmp );
}
n = sqlite3ValueBytes(pVal, pColl->enc);
for(; i<pIdx->nSample; i++){
int c;
int eSampletype = aSample[i].eType;
if( eSampletype<eType ) continue;
if( eSampletype!=eType ) break;
#ifndef SQLITE_OMIT_UTF16
if( pColl->enc!=SQLITE_UTF8 ){
int nSample;
char *zSample = sqlite3Utf8to16(
db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample
);
if( !zSample ){
assert( db->mallocFailed );
return SQLITE_NOMEM;
}
c = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
sqlite3DbFree(db, zSample);
}else
#endif
{
c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
}
if( c>=0 ){
if( c==0 ) isEq = 1;
break;
}
}
}
/* Otherwise, pRec must be smaller than sample $i and larger than
** sample ($i-1). */
assert( i==pIdx->nSample
|| sqlite3VdbeRecordCompare(aSample[i].n, aSample[i].p, pRec)>0
|| pParse->db->mallocFailed );
assert( i==0
|| sqlite3VdbeRecordCompare(aSample[i-1].n, aSample[i-1].p, pRec)<0
|| pParse->db->mallocFailed );
}
#endif /* ifdef SQLITE_DEBUG */
/* At this point, aSample[i] is the first sample that is greater than
** or equal to pVal. Or if i==pIdx->nSample, then all samples are less
** than pVal. If aSample[i]==pVal, then isEq==1.
** than pVal. If aSample[i]==pVal, then res==0.
*/
if( isEq ){
assert( i<pIdx->nSample );
aStat[0] = aSample[i].nLt;
aStat[1] = aSample[i].nEq;
if( res==0 ){
aStat[0] = aSample[i].anLt[iCol];
aStat[1] = aSample[i].anEq[iCol];
}else{
tRowcnt iLower, iUpper, iGap;
if( i==0 ){
iLower = 0;
iUpper = aSample[0].nLt;
iUpper = aSample[0].anLt[iCol];
}else{
iUpper = i>=pIdx->nSample ? n : aSample[i].nLt;
iLower = aSample[i-1].nEq + aSample[i-1].nLt;
iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol];
iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
}
aStat[1] = pIdx->avgEq;
aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 1);
if( iLower>=iUpper ){
iGap = 0;
}else{
@@ -2556,44 +2493,8 @@ static int whereKeyStats(
}
aStat[0] = iLower + iGap;
}
return SQLITE_OK;
}
#endif /* SQLITE_ENABLE_STAT3 */
/*
** If expression pExpr represents a literal value, set *pp to point to
** an sqlite3_value structure containing the same value, with affinity
** aff applied to it, before returning. It is the responsibility of the
** caller to eventually release this structure by passing it to
** sqlite3ValueFree().
**
** If the current parse is a recompile (sqlite3Reprepare()) and pExpr
** is an SQL variable that currently has a non-NULL value bound to it,
** create an sqlite3_value structure containing this value, again with
** affinity aff applied to it, instead.
**
** If neither of the above apply, set *pp to NULL.
**
** If an error occurs, return an error code. Otherwise, SQLITE_OK.
*/
#ifdef SQLITE_ENABLE_STAT3
static int valueFromExpr(
Parse *pParse,
Expr *pExpr,
u8 aff,
sqlite3_value **pp
){
if( pExpr->op==TK_VARIABLE
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
){
int iVar = pExpr->iColumn;
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
*pp = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, aff);
return SQLITE_OK;
}
return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
}
#endif
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/*
** This function is used to estimate the number of rows that will be visited
@@ -2610,103 +2511,155 @@ static int valueFromExpr(
** If either of the upper or lower bound is not present, then NULL is passed in
** place of the corresponding WhereTerm.
**
** The nEq parameter is passed the index of the index column subject to the
** range constraint. Or, equivalently, the number of equality constraints
** optimized by the proposed index scan. For example, assuming index p is
** on t1(a, b), and the SQL query is:
** The value in (pBuilder->pNew->u.btree.nEq) is the index of the index
** column subject to the range constraint. Or, equivalently, the number of
** equality constraints optimized by the proposed index scan. For example,
** assuming index p is on t1(a, b), and the SQL query is:
**
** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ...
**
** then nEq should be passed the value 1 (as the range restricted column,
** b, is the second left-most column of the index). Or, if the query is:
** then nEq is set to 1 (as the range restricted column, b, is the second
** left-most column of the index). Or, if the query is:
**
** ... FROM t1 WHERE a > ? AND a < ? ...
**
** then nEq should be passed 0.
** then nEq is set to 0.
**
** The returned value is an integer divisor to reduce the estimated
** search space. A return value of 1 means that range constraints are
** no help at all. A return value of 2 means range constraints are
** expected to reduce the search space by half. And so forth...
**
** In the absence of sqlite_stat3 ANALYZE data, each range inequality
** reduces the search space by a factor of 4. Hence a single constraint (x>?)
** results in a return of 4 and a range constraint (x>? AND x<?) results
** in a return of 16.
** When this function is called, *pnOut is set to the whereCost() of the
** number of rows that the index scan is expected to visit without
** considering the range constraints. If nEq is 0, this is the number of
** rows in the index. Assuming no error occurs, *pnOut is adjusted (reduced)
** to account for the range contraints pLower and pUpper.
**
** In the absence of sqlite_stat4 ANALYZE data, or if such data cannot be
** used, each range inequality reduces the search space by a factor of 4.
** Hence a pair of constraints (x>? AND x<?) reduces the expected number of
** rows visited by a factor of 16.
*/
static int whereRangeScanEst(
Parse *pParse, /* Parsing & code generating context */
Index *p, /* The index containing the range-compared column; "x" */
int nEq, /* index into p->aCol[] of the range-compared column */
WhereLoopBuilder *pBuilder,
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
WhereCost *pRangeDiv /* OUT: Reduce search space by this divisor */
WhereCost *pnOut /* IN/OUT: Number of rows visited */
){
int rc = SQLITE_OK;
int nOut = (int)*pnOut;
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
Index *p = pBuilder->pNew->u.btree.pIndex;
int nEq = pBuilder->pNew->u.btree.nEq;
if( nEq==0 && p->nSample && OptimizationEnabled(pParse->db, SQLITE_Stat3) ){
sqlite3_value *pRangeVal;
tRowcnt iLower = 0;
tRowcnt iUpper = p->aiRowEst[0];
if( p->nSample>0
&& nEq==pBuilder->nRecValid
&& nEq<p->nSampleCol
&& OptimizationEnabled(pParse->db, SQLITE_Stat3)
){
UnpackedRecord *pRec = pBuilder->pRec;
tRowcnt a[2];
u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
u8 aff;
/* Variable iLower will be set to the estimate of the number of rows in
** the index that are less than the lower bound of the range query. The
** lower bound being the concatenation of $P and $L, where $P is the
** key-prefix formed by the nEq values matched against the nEq left-most
** columns of the index, and $L is the value in pLower.
**
** Or, if pLower is NULL or $L cannot be extracted from it (because it
** is not a simple variable or literal value), the lower bound of the
** range is $P. Due to a quirk in the way whereKeyStats() works, even
** if $L is available, whereKeyStats() is called for both ($P) and
** ($P:$L) and the larger of the two returned values used.
**
** Similarly, iUpper is to be set to the estimate of the number of rows
** less than the upper bound of the range query. Where the upper bound
** is either ($P) or ($P:$U). Again, even if $U is available, both values
** of iUpper are requested of whereKeyStats() and the smaller used.
*/
tRowcnt iLower;
tRowcnt iUpper;
if( nEq==p->nColumn ){
aff = SQLITE_AFF_INTEGER;
}else{
aff = p->pTable->aCol[p->aiColumn[nEq]].affinity;
}
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
iUpper = p->aiRowEst[0];
}else{
/* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
whereKeyStats(pParse, p, pRec, 0, a);
iLower = a[0];
iUpper = a[0] + a[1];
}
/* If possible, improve on the iLower estimate using ($P:$L). */
if( pLower ){
int bOk; /* True if value is extracted from pExpr */
Expr *pExpr = pLower->pExpr->pRight;
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
if( rc==SQLITE_OK
&& whereKeyStats(pParse, p, pRangeVal, 0, a)==SQLITE_OK
){
iLower = a[0];
if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
whereKeyStats(pParse, p, pRec, 0, a);
iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
if( iNew>iLower ) iLower = iNew;
}
sqlite3ValueFree(pRangeVal);
}
if( rc==SQLITE_OK && pUpper ){
/* If possible, improve on the iUpper estimate using ($P:$U). */
if( pUpper ){
int bOk; /* True if value is extracted from pExpr */
Expr *pExpr = pUpper->pExpr->pRight;
rc = valueFromExpr(pParse, pExpr, aff, &pRangeVal);
assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
if( rc==SQLITE_OK
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
){
iUpper = a[0];
if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
if( rc==SQLITE_OK && bOk ){
tRowcnt iNew;
whereKeyStats(pParse, p, pRec, 1, a);
iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
if( iNew<iUpper ) iUpper = iNew;
}
sqlite3ValueFree(pRangeVal);
}
pBuilder->pRec = pRec;
if( rc==SQLITE_OK ){
WhereCost iBase = whereCost(p->aiRowEst[0]);
WhereCost nNew;
if( iUpper>iLower ){
iBase -= whereCost(iUpper - iLower);
nNew = whereCost(iUpper - iLower);
}else{
nNew = 10; assert( 10==whereCost(2) );
}
*pRangeDiv = iBase;
WHERETRACE(0x100, ("range scan regions: %u..%u div=%d\n",
(u32)iLower, (u32)iUpper, *pRangeDiv));
if( nNew<nOut ){
nOut = nNew;
}
*pnOut = (WhereCost)nOut;
WHERETRACE(0x100, ("range scan regions: %u..%u est=%d\n",
(u32)iLower, (u32)iUpper, nOut));
return SQLITE_OK;
}
}
#else
UNUSED_PARAMETER(pParse);
UNUSED_PARAMETER(p);
UNUSED_PARAMETER(nEq);
UNUSED_PARAMETER(pBuilder);
#endif
assert( pLower || pUpper );
*pRangeDiv = 0;
/* TUNING: Each inequality constraint reduces the search space 4-fold.
** A BETWEEN operator, therefore, reduces the search space 16-fold */
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
*pRangeDiv += 20; assert( 20==whereCost(4) );
nOut -= 20; assert( 20==whereCost(4) );
}
if( pUpper ){
*pRangeDiv += 20; assert( 20==whereCost(4) );
nOut -= 20; assert( 20==whereCost(4) );
}
if( nOut<10 ) nOut = 10;
*pnOut = (WhereCost)nOut;
return rc;
}
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Estimate the number of rows that will be returned based on
** an equality constraint x=VALUE and where that VALUE occurs in
@@ -2726,37 +2679,53 @@ static int whereRangeScanEst(
*/
static int whereEqualScanEst(
Parse *pParse, /* Parsing & code generating context */
Index *p, /* The index whose left-most column is pTerm */
WhereLoopBuilder *pBuilder,
Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */
tRowcnt *pnRow /* Write the revised row estimate here */
){
sqlite3_value *pRhs = 0; /* VALUE on right-hand side of pTerm */
Index *p = pBuilder->pNew->u.btree.pIndex;
int nEq = pBuilder->pNew->u.btree.nEq;
UnpackedRecord *pRec = pBuilder->pRec;
u8 aff; /* Column affinity */
int rc; /* Subfunction return code */
tRowcnt a[2]; /* Statistics */
int bOk;
assert( nEq>=1 );
assert( nEq<=(p->nColumn+1) );
assert( p->aSample!=0 );
assert( p->nSample>0 );
aff = p->pTable->aCol[p->aiColumn[0]].affinity;
if( pExpr ){
rc = valueFromExpr(pParse, pExpr, aff, &pRhs);
if( rc ) goto whereEqualScanEst_cancel;
}else{
pRhs = sqlite3ValueNew(pParse->db);
assert( pBuilder->nRecValid<nEq );
/* If values are not available for all fields of the index to the left
** of this one, no estimate can be made. Return SQLITE_NOTFOUND. */
if( pBuilder->nRecValid<(nEq-1) ){
return SQLITE_NOTFOUND;
}
if( pRhs==0 ) return SQLITE_NOTFOUND;
rc = whereKeyStats(pParse, p, pRhs, 0, a);
if( rc==SQLITE_OK ){
WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
*pnRow = a[1];
/* This is an optimization only. The call to sqlite3Stat4ProbeSetValue()
** below would return the same value. */
if( nEq>p->nColumn ){
*pnRow = 1;
return SQLITE_OK;
}
whereEqualScanEst_cancel:
sqlite3ValueFree(pRhs);
aff = p->pTable->aCol[p->aiColumn[nEq-1]].affinity;
rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk);
pBuilder->pRec = pRec;
if( rc!=SQLITE_OK ) return rc;
if( bOk==0 ) return SQLITE_NOTFOUND;
pBuilder->nRecValid = nEq;
whereKeyStats(pParse, p, pRec, 0, a);
WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
*pnRow = a[1];
return rc;
}
#endif /* defined(SQLITE_ENABLE_STAT3) */
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
#ifdef SQLITE_ENABLE_STAT3
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Estimate the number of rows that will be returned based on
** an IN constraint where the right-hand side of the IN operator
@@ -2775,10 +2744,12 @@ whereEqualScanEst_cancel:
*/
static int whereInScanEst(
Parse *pParse, /* Parsing & code generating context */
Index *p, /* The index whose left-most column is pTerm */
WhereLoopBuilder *pBuilder,
ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
tRowcnt *pnRow /* Write the revised row estimate here */
){
Index *p = pBuilder->pNew->u.btree.pIndex;
int nRecValid = pBuilder->nRecValid;
int rc = SQLITE_OK; /* Subfunction return code */
tRowcnt nEst; /* Number of rows for a single term */
tRowcnt nRowEst = 0; /* New estimate of the number of rows */
@@ -2787,17 +2758,20 @@ static int whereInScanEst(
assert( p->aSample!=0 );
for(i=0; rc==SQLITE_OK && i<pList->nExpr; i++){
nEst = p->aiRowEst[0];
rc = whereEqualScanEst(pParse, p, pList->a[i].pExpr, &nEst);
rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst);
nRowEst += nEst;
pBuilder->nRecValid = nRecValid;
}
if( rc==SQLITE_OK ){
if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
*pnRow = nRowEst;
WHERETRACE(0x100,("IN row estimate: est=%g\n", nRowEst));
}
assert( pBuilder->nRecValid==nRecValid );
return rc;
}
#endif /* defined(SQLITE_ENABLE_STAT3) */
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/*
** Disable a term in the WHERE clause. Except, do not disable the term
@@ -2826,6 +2800,7 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
if( pTerm
&& (pTerm->wtFlags & TERM_CODED)==0
&& (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin))
&& (pLevel->notReady & pTerm->prereqAll)==0
){
pTerm->wtFlags |= TERM_CODED;
if( pTerm->iParent>=0 ){
@@ -3035,7 +3010,7 @@ static int codeAllEqualityTerms(
/* Evaluate the equality constraints
*/
assert( zAff==0 || strlen(zAff)>=nEq );
assert( zAff==0 || (int)strlen(zAff)>=nEq );
for(j=0; j<nEq; j++){
int r1;
pTerm = pLoop->aLTerm[j];
@@ -3251,7 +3226,6 @@ static Bitmask codeOneLoopStart(
int addrCont; /* Jump here to continue with next cycle */
int iRowidReg = 0; /* Rowid is stored in this register, if not zero */
int iReleaseReg = 0; /* Temp register to free before returning */
Bitmask newNotReady; /* Return value */
pParse = pWInfo->pParse;
v = pParse->pVdbe;
@@ -3261,6 +3235,7 @@ static Bitmask codeOneLoopStart(
pLoop = pLevel->pWLoop;
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
iCur = pTabItem->iCursor;
pLevel->notReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur);
bRev = (pWInfo->revMask>>iLevel)&1;
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
@@ -3913,7 +3888,6 @@ static Bitmask codeOneLoopStart(
pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk);
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}
newNotReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur);
/* Insert code to test every subexpression that can be completely
** computed using the current set of tables.
@@ -3923,7 +3897,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & newNotReady)!=0 ){
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
testcase( pWInfo->untestedTerms==0
&& (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 );
pWInfo->untestedTerms = 1;
@@ -3955,7 +3929,7 @@ static Bitmask codeOneLoopStart(
if( pLevel->iLeftJoin ) continue;
pE = pTerm->pExpr;
assert( !ExprHasProperty(pE, EP_FromJoin) );
assert( (pTerm->prereqRight & newNotReady)!=0 );
assert( (pTerm->prereqRight & pLevel->notReady)!=0 );
pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, WO_EQ|WO_IN, 0);
if( pAlt==0 ) continue;
if( pAlt->wtFlags & (TERM_CODED) ) continue;
@@ -3983,7 +3957,7 @@ static Bitmask codeOneLoopStart(
testcase( pTerm->wtFlags & TERM_VIRTUAL );
testcase( pTerm->wtFlags & TERM_CODED );
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
if( (pTerm->prereqAll & newNotReady)!=0 ){
if( (pTerm->prereqAll & pLevel->notReady)!=0 ){
assert( pWInfo->untestedTerms );
continue;
}
@@ -3994,7 +3968,7 @@ static Bitmask codeOneLoopStart(
}
sqlite3ReleaseTempReg(pParse, iReleaseReg);
return newNotReady;
return pLevel->notReady;
}
#ifdef WHERETRACE_ENABLED
@@ -4095,8 +4069,11 @@ static int whereLoopResize(sqlite3 *db, WhereLoop *p, int n){
** Transfer content from the second pLoop into the first.
*/
static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){
if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM;
whereLoopClearUnion(db, pTo);
if( whereLoopResize(db, pTo, pFrom->nLTerm) ){
memset(&pTo->u, 0, sizeof(pTo->u));
return SQLITE_NOMEM;
}
memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ);
memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0]));
if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){
@@ -4204,15 +4181,17 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
if( (p->prereq & pTemplate->prereq)==p->prereq
&& p->rSetup<=pTemplate->rSetup
&& p->rRun<=pTemplate->rRun
&& p->nOut<=pTemplate->nOut
){
/* This branch taken when p is equal or better than pTemplate in
** all of (1) dependences (2) setup-cost, and (3) run-cost. */
** all of (1) dependencies (2) setup-cost, (3) run-cost, and
** (4) number of output rows. */
assert( p->rSetup==pTemplate->rSetup );
if( p->nLTerm<pTemplate->nLTerm
if( p->prereq==pTemplate->prereq
&& p->nLTerm<pTemplate->nLTerm
&& (p->wsFlags & WHERE_INDEXED)!=0
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
&& p->u.btree.pIndex==pTemplate->u.btree.pIndex
&& p->prereq==pTemplate->prereq
){
/* Overwrite an existing WhereLoop with an similar one that uses
** more terms of the index */
@@ -4226,11 +4205,13 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rRun>=pTemplate->rRun
&& p->nOut>=pTemplate->nOut
&& ALWAYS(p->rSetup>=pTemplate->rSetup) /* See SETUP-INVARIANT above */
){
/* Overwrite an existing WhereLoop with a better one: one that is
** better at one of (1) dependences, (2) setup-cost, or (3) run-cost
** and is no worse in any of those categories. */
** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
** or (4) number of output rows, and is no worse in any of those
** categories. */
pNext = p->pNextLoop;
break;
}
@@ -4342,12 +4323,18 @@ static int whereLoopAddBtreeIndex(
rLogSize = estLog(whereCost(pProbe->aiRowEst[0]));
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
int nIn = 0;
if( pTerm->prereqRight & pNew->maskSelf ) continue;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nRecValid = pBuilder->nRecValid;
#endif
if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
&& (iCol<0 || pSrc->pTab->aCol[iCol].notNull)
){
continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */
}
if( pTerm->prereqRight & pNew->maskSelf ) continue;
assert( pNew->nOut==saved_nOut );
pNew->wsFlags = saved_wsFlags;
pNew->u.btree.nEq = saved_nEq;
pNew->nLTerm = saved_nLTerm;
@@ -4404,25 +4391,30 @@ static int whereLoopAddBtreeIndex(
}
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
/* Adjust nOut and rRun for STAT3 range values */
WhereCost rDiv;
whereRangeScanEst(pParse, pProbe, pNew->u.btree.nEq,
pBtm, pTop, &rDiv);
pNew->nOut = saved_nOut>rDiv+10 ? saved_nOut - rDiv : 10;
assert( pNew->nOut==saved_nOut );
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, &pNew->nOut);
}
#ifdef SQLITE_ENABLE_STAT3
if( pNew->u.btree.nEq==1 && pProbe->nSample
&& OptimizationEnabled(db, SQLITE_Stat3) ){
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( nInMul==0
&& pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
&& OptimizationEnabled(db, SQLITE_Stat3)
){
Expr *pExpr = pTerm->pExpr;
tRowcnt nOut = 0;
if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){
testcase( pTerm->eOperator & WO_EQ );
testcase( pTerm->eOperator & WO_ISNULL );
rc = whereEqualScanEst(pParse, pProbe, pTerm->pExpr->pRight, &nOut);
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else if( (pTerm->eOperator & WO_IN)
&& !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){
rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut);
&& !ExprHasProperty(pExpr, EP_xIsSelect) ){
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
assert( nOut==0 || rc==SQLITE_OK );
if( nOut ) pNew->nOut = whereCost(nOut);
if( nOut ){
nOut = whereCost(nOut);
pNew->nOut = MIN(nOut, saved_nOut);
}
}
#endif
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
@@ -4439,6 +4431,10 @@ static int whereLoopAddBtreeIndex(
){
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nInMul+nIn);
}
pNew->nOut = saved_nOut;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
pBuilder->nRecValid = nRecValid;
#endif
}
pNew->prereq = saved_prereq;
pNew->u.btree.nEq = saved_nEq;
@@ -4668,7 +4664,13 @@ static int whereLoopAddBtree(
if( rc ) break;
}
}
rc = whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, 0);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
sqlite3Stat4ProbeFree(pBuilder->pRec);
pBuilder->nRecValid = 0;
pBuilder->pRec = 0;
#endif
/* If there was an INDEXED BY clause, then only that one index is
** considered. */
@@ -5914,7 +5916,7 @@ WhereInfo *sqlite3WhereBegin(
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){
Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet);
if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy);
if( sWLB.pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, sWLB.pOrderBy);
while( pWInfo->nLevel>=2 ){
WhereTerm *pTerm, *pEnd;
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
+2 -1
View File
@@ -847,7 +847,8 @@ do_test alter-14.2 {
set system_table_list {1 sqlite_master}
catchsql ANALYZE
ifcapable analyze { lappend system_table_list 2 sqlite_stat1 }
ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 }
ifcapable stat3 { lappend system_table_list 3 sqlite_stat3 }
ifcapable stat4 { lappend system_table_list 4 sqlite_stat4 }
foreach {tn tbl} $system_table_list {
do_test alter-15.$tn.1 {
+5
View File
@@ -143,6 +143,11 @@ do_test alter4-2.6 {
alter table t1 add column d DEFAULT CURRENT_TIME;
}
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.7 {
catchsql {
alter table t1 add column d default (-+1);
}
} {1 {Cannot add a column with non-constant default}}
do_test alter4-2.99 {
execsql {
DROP TABLE t1;
+17 -17
View File
@@ -288,7 +288,7 @@ do_test analyze-4.3 {
} {}
# Verify that DROP TABLE and DROP INDEX remove entries from the
# sqlite_stat1 and sqlite_stat3 tables.
# sqlite_stat1, sqlite_stat3 and sqlite_stat4 tables.
#
do_test analyze-5.0 {
execsql {
@@ -306,12 +306,13 @@ do_test analyze-5.0 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
ifcapable stat4 {set stat sqlite_stat4} else {set stat sqlite_stat3}
do_test analyze-5.1 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
}
do_test analyze-5.2 {
@@ -321,12 +322,12 @@ do_test analyze-5.2 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
do_test analyze-5.3 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
}
do_test analyze-5.4 {
@@ -336,12 +337,12 @@ do_test analyze-5.4 {
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
}
} {t4i1 t4i2 t4}
ifcapable stat3 {
ifcapable stat4||stat3 {
do_test analyze-5.5 {
execsql {
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
}
execsql "
SELECT DISTINCT idx FROM $stat ORDER BY 1;
SELECT DISTINCT tbl FROM $stat ORDER BY 1;
"
} {t4i1 t4i2 t4}
}
@@ -360,5 +361,4 @@ do_test analyze-99.1 {
}
} {1 {malformed database schema (sqlite_stat1) - near "nonsense": syntax error}}
finish_test
+8 -3
View File
@@ -17,7 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -95,7 +95,13 @@ do_test analyze3-1.1.1 {
COMMIT;
ANALYZE;
}
} {}
ifcapable stat4 {
execsql { SELECT count(*)>0 FROM sqlite_stat4; }
} else {
execsql { SELECT count(*)>0 FROM sqlite_stat3; }
}
} {1}
do_eqp_test analyze3-1.1.2 {
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
@@ -312,7 +318,6 @@ do_test analyze3-3.1 {
execsql COMMIT
execsql ANALYZE
} {}
do_test analyze3-3.2.1 {
set S [sqlite3_prepare_v2 db "SELECT * FROM t1 WHERE b>?" -1 dummy]
sqlite3_expired $S
+42 -8
View File
@@ -10,14 +10,14 @@
#***********************************************************************
#
# This file implements tests for SQLite library. The focus of the tests
# in this file is the use of the sqlite_stat3 histogram data on tables
# in this file is the use of the sqlite_stat4 histogram data on tables
# with many repeated values and only a few distinct values.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -28,6 +28,17 @@ proc eqp {sql {db db}} {
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
}
proc alpha {blob} {
set ret ""
foreach c [split $blob {}] {
if {[string is alpha $c]} {append ret $c}
}
return $ret
}
db func alpha alpha
db func lindex lindex
unset -nocomplain i t u v w x y z
do_test analyze5-1.0 {
db eval {CREATE TABLE t1(t,u,v TEXT COLLATE nocase,w,x,y,z)}
@@ -55,17 +66,40 @@ do_test analyze5-1.0 {
CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s
CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3
ANALYZE;
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
}
ifcapable stat4 {
db eval {
SELECT DISTINCT lindex(test_decode(sample),0)
FROM sqlite_stat4 WHERE idx='t1u' ORDER BY nlt;
}
} else {
db eval {
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
}
}
} {alpha bravo charlie delta}
do_test analyze5-1.1 {
db eval {SELECT DISTINCT lower(sample) FROM sqlite_stat3 WHERE idx='t1v'
ORDER BY 1}
ifcapable stat4 {
db eval {
SELECT DISTINCT lower(lindex(test_decode(sample), 0))
FROM sqlite_stat4 WHERE idx='t1v' ORDER BY 1
}
} else {
db eval {
SELECT lower(sample) FROM sqlite_stat3 WHERE idx='t1v' ORDER BY 1
}
}
} {alpha bravo charlie delta}
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
ifcapable stat4 {
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat4 GROUP BY 1 ORDER BY 1}
} {t1t 8 t1u 8 t1v 8 t1w 8 t1x 8 t1y 9 t1z 8}
} else {
do_test analyze5-1.2 {
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
}
# Verify that range queries generate the correct row count estimates
#
+1 -1
View File
@@ -17,7 +17,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
+5 -4
View File
@@ -82,14 +82,14 @@ do_test analyze7-3.1 {
do_test analyze7-3.2.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
ifcapable stat3 {
# If ENABLE_STAT3 is defined, SQLite comes up with a different estimated
ifcapable stat4||stat3 {
# If ENABLE_STAT4 is defined, SQLite comes up with a different estimated
# row count for (c=2) than it does for (c=?).
do_test analyze7-3.2.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}}
} else {
# If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the
# If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the
# same as that for (c=?).
do_test analyze7-3.2.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
@@ -98,7 +98,8 @@ ifcapable stat3 {
do_test analyze7-3.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}}
ifcapable {!stat3} {
ifcapable {!stat4 && !stat3} {
do_test analyze7-3.4 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
+13 -1
View File
@@ -16,7 +16,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
@@ -84,7 +84,19 @@ do_test 2.1 {
# There are many more values of c between 0 and 100000 than there are
# between 800000 and 900000. So t1c is more selective for the latter
# range.
#
# Test 3.2 is a little unstable. It depends on the planner estimating
# that (b BETWEEN 50 AND 54) will match more rows than (c BETWEEN
# 800000 AND 900000). Which is a pretty close call (50 vs. 32), so
# the planner could get it wrong with an unlucky set of samples. This
# case happens to work, but others ("b BETWEEN 40 AND 44" for example)
# will fail.
#
do_execsql_test 3.0 {
SELECT count(*) FROM t1 WHERE b BETWEEN 50 AND 54;
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000;
SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000;
} {50 376 32}
do_test 3.1 {
eqp {SELECT * FROM t1 WHERE b BETWEEN 50 AND 54 AND c BETWEEN 0 AND 100000}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
+952
View File
@@ -0,0 +1,952 @@
# 2013 August 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains automated tests used to verify that the sqlite_stat4
# functionality is working.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix analyze9
ifcapable !stat4 {
finish_test
return
}
proc s {blob} {
set ret ""
binary scan $blob c* bytes
foreach b $bytes {
set t [binary format c $b]
if {[string is print $t]} {
append ret $t
} else {
append ret .
}
}
return $ret
}
db function s s
do_execsql_test 1.0 {
CREATE TABLE t1(a TEXT, b TEXT);
INSERT INTO t1 VALUES('(0)', '(0)');
INSERT INTO t1 VALUES('(1)', '(1)');
INSERT INTO t1 VALUES('(2)', '(2)');
INSERT INTO t1 VALUES('(3)', '(3)');
INSERT INTO t1 VALUES('(4)', '(4)');
CREATE INDEX i1 ON t1(a, b);
} {}
do_execsql_test 1.1 {
ANALYZE;
} {}
do_execsql_test 1.2 {
SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4;
} {
t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1}
t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2}
t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3}
t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4}
t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5}
}
if {[permutation] != "utf16"} {
do_execsql_test 1.3 {
SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4;
} {
t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0)
t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1).
t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2).
t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3).
t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4).
}
}
#-------------------------------------------------------------------------
# This is really just to test SQL user function "test_decode".
#
reset_db
do_execsql_test 2.1 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES('some text', 14, NULL);
INSERT INTO t1 VALUES(22.0, NULL, x'656667');
CREATE INDEX i1 ON t1(a, b, c);
ANALYZE;
SELECT test_decode(sample) FROM sqlite_stat4;
} {
{22.0 NULL x'656667' 2}
{{some text} 14 NULL 1}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 3.1 {
CREATE TABLE t2(a, b);
CREATE INDEX i2 ON t2(a, b);
BEGIN;
}
do_test 3.2 {
for {set i 0} {$i < 1000} {incr i} {
set a [expr $i / 10]
set b [expr int(rand() * 15.0)]
execsql { INSERT INTO t2 VALUES($a, $b) }
}
execsql COMMIT
} {}
db func lindex lindex
# Each value of "a" occurs exactly 10 times in the table.
#
do_execsql_test 3.3.1 {
SELECT count(*) FROM t2 GROUP BY a;
} [lrange [string repeat "10 " 100] 0 99]
# The first element in the "nEq" list of all samples should therefore be 10.
#
do_execsql_test 3.3.2 {
ANALYZE;
SELECT lindex(nEq, 0) FROM sqlite_stat4;
} [lrange [string repeat "10 " 100] 0 23]
#-------------------------------------------------------------------------
#
do_execsql_test 3.4 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1, 1, 'one-a');
INSERT INTO t1 VALUES(11, 1, 'one-b');
INSERT INTO t1 VALUES(21, 1, 'one-c');
INSERT INTO t1 VALUES(31, 1, 'one-d');
INSERT INTO t1 VALUES(41, 1, 'one-e');
INSERT INTO t1 VALUES(51, 1, 'one-f');
INSERT INTO t1 VALUES(61, 1, 'one-g');
INSERT INTO t1 VALUES(71, 1, 'one-h');
INSERT INTO t1 VALUES(81, 1, 'one-i');
INSERT INTO t1 VALUES(91, 1, 'one-j');
INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
CREATE INDEX t1b ON t1(b);
ANALYZE;
SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
} {three-d three-e three-f}
#-------------------------------------------------------------------------
# These tests verify that the sample selection for stat4 appears to be
# working as designed.
#
reset_db
db func lindex lindex
db func lrange lrange
do_execsql_test 4.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(c, b, a);
}
proc insert_filler_rows_n {iStart args} {
set A(-ncopy) 1
set A(-nval) 1
foreach {k v} $args {
if {[info exists A($k)]==0} { error "no such option: $k" }
set A($k) $v
}
if {[llength $args] % 2} {
error "option requires an argument: [lindex $args end]"
}
for {set i 0} {$i < $A(-nval)} {incr i} {
set iVal [expr $iStart+$i]
for {set j 0} {$j < $A(-ncopy)} {incr j} {
execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
}
}
}
do_test 4.1 {
execsql { BEGIN }
insert_filler_rows_n 0 -ncopy 10 -nval 19
insert_filler_rows_n 20 -ncopy 1 -nval 100
execsql {
INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
ANALYZE;
SELECT count(*) FROM sqlite_stat4;
SELECT count(*) FROM t1;
}
} {24 297}
do_execsql_test 4.2 {
SELECT
neq,
lrange(nlt, 0, 2),
lrange(ndlt, 0, 2),
lrange(test_decode(sample), 0, 2)
FROM sqlite_stat4
ORDER BY rowid LIMIT 16;
} {
{10 10 10 1} {0 0 0} {0 0 0} {0 0 0}
{10 10 10 1} {10 10 10} {1 1 1} {1 1 1}
{10 10 10 1} {20 20 20} {2 2 2} {2 2 2}
{10 10 10 1} {30 30 30} {3 3 3} {3 3 3}
{10 10 10 1} {40 40 40} {4 4 4} {4 4 4}
{10 10 10 1} {50 50 50} {5 5 5} {5 5 5}
{10 10 10 1} {60 60 60} {6 6 6} {6 6 6}
{10 10 10 1} {70 70 70} {7 7 7} {7 7 7}
{10 10 10 1} {80 80 80} {8 8 8} {8 8 8}
{10 10 10 1} {90 90 90} {9 9 9} {9 9 9}
{10 10 10 1} {100 100 100} {10 10 10} {10 10 10}
{10 10 10 1} {110 110 110} {11 11 11} {11 11 11}
{10 10 10 1} {120 120 120} {12 12 12} {12 12 12}
{10 10 10 1} {130 130 130} {13 13 13} {13 13 13}
{10 10 10 1} {140 140 140} {14 14 14} {14 14 14}
{10 10 10 1} {150 150 150} {15 15 15} {15 15 15}
}
do_execsql_test 4.3 {
SELECT
neq,
lrange(nlt, 0, 2),
lrange(ndlt, 0, 2),
lrange(test_decode(sample), 0, 1)
FROM sqlite_stat4
ORDER BY rowid DESC LIMIT 2;
} {
{2 1 1 1} {295 296 296} {120 122 125} {201 4}
{5 3 1 1} {290 290 290} {119 119 119} {200 1}
}
do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
# Check that the perioidic samples are present.
do_execsql_test 4.6 {
SELECT count(*) FROM sqlite_stat4
WHERE lindex(test_decode(sample), 3) IN
('34', '68', '102', '136', '170', '204', '238', '272')
} {8}
reset_db
do_test 4.7 {
execsql {
BEGIN;
CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
CREATE INDEX i1 ON t1(o);
}
for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
execsql { INSERT INTO t1 VALUES('x', $i) }
}
execsql {
COMMIT;
ANALYZE;
SELECT count(*) FROM sqlite_stat4;
}
} {8}
do_execsql_test 4.8 {
SELECT test_decode(sample) FROM sqlite_stat4;
} {
{x 211} {x 423} {x 635} {x 847}
{x 1590} {x 3710} {x 5830} {x 7950}
}
#-------------------------------------------------------------------------
# The following would cause a crash at one point.
#
reset_db
do_execsql_test 5.1 {
PRAGMA encoding = 'utf-16';
CREATE TABLE t0(v);
ANALYZE;
}
#-------------------------------------------------------------------------
# This was also crashing (corrupt sqlite_stat4 table).
#
reset_db
do_execsql_test 6.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
PRAGMA writable_schema = 1;
CREATE TEMP TABLE x1 AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4
ORDER BY (rowid%5), rowid;
DELETE FROM sqlite_stat4;
INSERT INTO sqlite_stat4 SELECT * FROM x1;
PRAGMA writable_schema = 0;
ANALYZE sqlite_master;
}
do_execsql_test 6.2 {
SELECT * FROM t1 WHERE a = 'abc';
}
#-------------------------------------------------------------------------
# The following tests experiment with adding corrupted records to the
# 'sample' column of the sqlite_stat4 table.
#
reset_db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test 7.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
UPDATE sqlite_stat4 SET sample = X'' WHERE rowid = 1;
ANALYZE sqlite_master;
}
do_execsql_test 7.2 {
UPDATE sqlite_stat4 SET sample = X'FFFF';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.3 {
ANALYZE;
UPDATE sqlite_stat4 SET neq = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.4 {
ANALYZE;
UPDATE sqlite_stat4 SET ndlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 3;
} {3 3}
do_execsql_test 7.5 {
ANALYZE;
UPDATE sqlite_stat4 SET nlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 5;
} {5 5}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
CREATE TABLE t1(x TEXT);
CREATE INDEX i1 ON t1(x);
INSERT INTO t1 VALUES('1');
INSERT INTO t1 VALUES('2');
INSERT INTO t1 VALUES('3');
INSERT INTO t1 VALUES('4');
ANALYZE;
}
do_execsql_test 8.2 {
SELECT * FROM t1 WHERE x = 3;
} {3}
#-------------------------------------------------------------------------
# Check that the bug fixed by [91733bc485] really is fixed.
#
reset_db
do_execsql_test 9.1 {
CREATE TABLE t1(a, b, c, d, e);
CREATE INDEX i1 ON t1(a, b, c, d);
CREATE INDEX i2 ON t1(e);
}
do_test 9.2 {
execsql BEGIN;
for {set i 0} {$i < 100} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
for {set i 0} {$i < 20} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
}
for {set i 102} {$i < 200} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
execsql COMMIT
execsql ANALYZE
} {}
do_eqp_test 9.3.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
} {/t1 USING INDEX i2/}
do_eqp_test 9.3.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
} {/t1 USING INDEX i1/}
set value_d [expr 101]
do_eqp_test 9.4.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i2/}
set value_d [expr 99]
do_eqp_test 9.4.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i1/}
#-------------------------------------------------------------------------
# Check that the planner takes stat4 data into account when considering
# "IS NULL" and "IS NOT NULL" constraints.
#
do_execsql_test 10.1.1 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a, b);
CREATE INDEX t3a ON t3(a);
CREATE INDEX t3b ON t3(b);
}
do_test 10.1.2 {
for {set i 1} {$i < 100} {incr i} {
if {$i>90} { set a $i } else { set a NULL }
set b [expr $i % 5]
execsql "INSERT INTO t3 VALUES($a, $b)"
}
execsql ANALYZE
} {}
do_eqp_test 10.1.3 {
SELECT * FROM t3 WHERE a IS NULL AND b = 2
} {/t3 USING INDEX t3b/}
do_eqp_test 10.1.4 {
SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2
} {/t3 USING INDEX t3a/}
do_execsql_test 10.2.1 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(x, a, b);
CREATE INDEX t3a ON t3(x, a);
CREATE INDEX t3b ON t3(x, b);
}
do_test 10.2.2 {
for {set i 1} {$i < 100} {incr i} {
if {$i>90} { set a $i } else { set a NULL }
set b [expr $i % 5]
execsql "INSERT INTO t3 VALUES('xyz', $a, $b)"
}
execsql ANALYZE
} {}
do_eqp_test 10.2.3 {
SELECT * FROM t3 WHERE x = 'xyz' AND a IS NULL AND b = 2
} {/t3 USING INDEX t3b/}
do_eqp_test 10.2.4 {
SELECT * FROM t3 WHERE x = 'xyz' AND a IS NOT NULL AND b = 2
} {/t3 USING INDEX t3a/}
#-------------------------------------------------------------------------
# Check that stat4 data is used correctly with non-default collation
# sequences.
#
foreach {tn schema} {
1 {
CREATE TABLE t4(a COLLATE nocase, b);
CREATE INDEX t4a ON t4(a);
CREATE INDEX t4b ON t4(b);
}
2 {
CREATE TABLE t4(a, b);
CREATE INDEX t4a ON t4(a COLLATE nocase);
CREATE INDEX t4b ON t4(b);
}
} {
drop_all_tables
do_test 11.$tn.1 { execsql $schema } {}
do_test 11.$tn.2 {
for {set i 0} {$i < 100} {incr i} {
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
set b [expr $i % 5]
execsql { INSERT INTO t4 VALUES($a, $b) }
}
execsql ANALYZE
} {}
do_eqp_test 11.$tn.3 {
SELECT * FROM t4 WHERE a = 'def' AND b = 3;
} {/t4 USING INDEX t4b/}
if {$tn==1} {
set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;"
do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/}
} else {
set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;"
do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/}
set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;"
do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/}
}
}
foreach {tn schema} {
1 {
CREATE TABLE t4(x, a COLLATE nocase, b);
CREATE INDEX t4a ON t4(x, a);
CREATE INDEX t4b ON t4(x, b);
}
2 {
CREATE TABLE t4(x, a, b);
CREATE INDEX t4a ON t4(x, a COLLATE nocase);
CREATE INDEX t4b ON t4(x, b);
}
} {
drop_all_tables
do_test 12.$tn.1 { execsql $schema } {}
do_test 12.$tn.2 {
for {set i 0} {$i < 100} {incr i} {
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
set b [expr $i % 5]
execsql { INSERT INTO t4 VALUES(X'abcdef', $a, $b) }
}
execsql ANALYZE
} {}
do_eqp_test 12.$tn.3 {
SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'def' AND b = 3;
} {/t4 USING INDEX t4b/}
if {$tn==1} {
set sql "SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' AND b = 3;"
do_eqp_test 12.$tn.4 $sql {/t4 USING INDEX t4a/}
} else {
set sql {
SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' COLLATE nocase AND b = 3
}
do_eqp_test 12.$tn.5 $sql {/t4 USING INDEX t4a/}
set sql {
SELECT * FROM t4 WHERE x=X'abcdef' AND a COLLATE nocase = 'abc' AND b = 3
}
do_eqp_test 12.$tn.6 $sql {/t4 USING INDEX t4a/}
}
}
#-------------------------------------------------------------------------
# Check that affinities are taken into account when using stat4 data to
# estimate the number of rows scanned by a rowid constraint.
#
drop_all_tables
do_test 13.1 {
execsql {
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b, c);
}
for {set i 0} {$i<100} {incr i} {
if {$i %2} {set a abc} else {set a def}
execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) }
}
execsql ANALYZE
} {}
do_eqp_test 13.2.1 {
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20
} {/SEARCH TABLE t1 USING INDEX i1/}
do_eqp_test 13.2.2 {
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20
} {/SEARCH TABLE t1 USING INDEX i1/}
do_eqp_test 13.3.1 {
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20
} {/SEARCH TABLE t1 USING INDEX i2/}
do_eqp_test 13.3.2 {
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20
} {/SEARCH TABLE t1 USING INDEX i2/}
#-------------------------------------------------------------------------
# Check also that affinities are taken into account when using stat4 data
# to estimate the number of rows scanned by any other constraint on a
# column other than the leftmost.
#
drop_all_tables
do_test 14.1 {
execsql { CREATE TABLE t1(a, b INTEGER, c) }
for {set i 0} {$i<100} {incr i} {
set c [expr $i % 3]
execsql { INSERT INTO t1 VALUES('ott', $i, $c) }
}
execsql {
CREATE INDEX i1 ON t1(a, b);
CREATE INDEX i2 ON t1(c);
ANALYZE;
}
} {}
do_eqp_test 13.2.1 {
SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1
} {/SEARCH TABLE t1 USING INDEX i1/}
do_eqp_test 13.2.2 {
SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1
} {/SEARCH TABLE t1 USING INDEX i1/}
#-------------------------------------------------------------------------
# By default, 16 non-periodic samples are collected for the stat4 table.
# The following tests attempt to verify that the most common keys are
# being collected.
#
proc check_stat4 {tn} {
db eval ANALYZE
db eval {SELECT a, b, c, d FROM t1} {
incr k($a)
incr k([list $a $b])
incr k([list $a $b $c])
if { [info exists k([list $a $b $c $d])]==0 } { incr nRow }
incr k([list $a $b $c $d])
}
set L [list]
foreach key [array names k] {
lappend L [list $k($key) $key]
}
set nSample $nRow
if {$nSample>16} {set nSample 16}
set nThreshold [lindex [lsort -decr -integer -index 0 $L] [expr $nSample-1] 0]
foreach key [array names k] {
if {$k($key)>$nThreshold} {
set expect($key) 1
}
if {$k($key)==$nThreshold} {
set possible($key) 1
}
}
set nPossible [expr $nSample - [llength [array names expect]]]
#puts "EXPECT: [array names expect]"
#puts "POSSIBLE($nPossible/[array size possible]): [array names possible]"
#puts "HAVE: [db eval {SELECT test_decode(sample) FROM sqlite_stat4 WHERE idx='i1'}]"
db eval {SELECT test_decode(sample) AS s FROM sqlite_stat4 WHERE idx='i1'} {
set seen 0
for {set i 0} {$i<4} {incr i} {
unset -nocomplain expect([lrange $s 0 $i])
if {[info exists possible([lrange $s 0 $i])]} {
set seen 1
unset -nocomplain possible([lrange $s 0 $i])
}
}
if {$seen} {incr nPossible -1}
}
if {$nPossible<0} {set nPossible 0}
set res [list [llength [array names expect]] $nPossible]
uplevel [list do_test $tn [list set {} $res] {0 0}]
}
drop_all_tables
do_test 14.1.1 {
execsql {
CREATE TABLE t1(a,b,c,d);
CREATE INDEX i1 ON t1(a,b,c,d);
}
for {set i 0} {$i < 160} {incr i} {
execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) }
if {($i % 10)==0} { execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) } }
}
} {}
check_stat4 14.1.2
do_test 14.2.1 {
execsql { DELETE FROM t1 }
for {set i 0} {$i < 1600} {incr i} {
execsql { INSERT INTO t1 VALUES($i/10,$i/17,$i/27,$i/37) }
}
} {}
check_stat4 14.2.2
do_test 14.3.1 {
for {set i 0} {$i < 10} {incr i} {
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
}
} {}
check_stat4 14.3.2
do_test 14.4.1 {
execsql {DELETE FROM t1}
for {set i 1} {$i < 160} {incr i} {
set b [expr $i % 10]
if {$b==0 || $b==2} {set b 1}
execsql { INSERT INTO t1 VALUES($i/10,$b,$i,$i) }
}
} {}
check_stat4 14.4.2
db func lrange lrange
db func lindex lindex
do_execsql_test 14.4.3 {
SELECT lrange(test_decode(sample), 0, 1) AS s FROM sqlite_stat4
WHERE lindex(s, 1)=='1' ORDER BY rowid
} {
{0 1} {1 1} {2 1} {3 1}
{4 1} {5 1} {6 1} {7 1}
{8 1} {9 1} {10 1} {11 1}
{12 1} {13 1} {14 1} {15 1}
}
#-------------------------------------------------------------------------
# Test that nothing untoward happens if the stat4 table contains entries
# for indexes that do not exist. Or NULL values in the idx column.
# Or NULL values in any of the other columns.
#
drop_all_tables
do_execsql_test 15.1 {
CREATE TABLE x1(a, b, UNIQUE(a, b));
INSERT INTO x1 VALUES(1, 2);
INSERT INTO x1 VALUES(3, 4);
INSERT INTO x1 VALUES(5, 6);
ANALYZE;
INSERT INTO sqlite_stat4 VALUES(NULL, NULL, NULL, NULL, NULL, NULL);
}
db close
sqlite3 db test.db
do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.3 {
INSERT INTO sqlite_stat4 VALUES(42, 42, 42, 42, 42, 42);
}
db close
sqlite3 db test.db
do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.5 {
UPDATE sqlite_stat1 SET stat = NULL;
}
db close
sqlite3 db test.db
do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.7 {
ANALYZE;
UPDATE sqlite_stat1 SET tbl = 'no such tbl';
}
db close
sqlite3 db test.db
do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.9 {
ANALYZE;
UPDATE sqlite_stat4 SET neq = NULL, nlt=NULL, ndlt=NULL;
}
db close
sqlite3 db test.db
do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6}
# This is just for coverage....
do_execsql_test 15.11 {
ANALYZE;
UPDATE sqlite_stat1 SET stat = stat || ' unordered';
}
db close
sqlite3 db test.db
do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6}
#-------------------------------------------------------------------------
# Test that allocations used for sqlite_stat4 samples are included in
# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED.
#
set one [string repeat x 1000]
set two [string repeat x 2000]
do_test 16.1 {
reset_db
execsql {
CREATE TABLE t1(a, UNIQUE(a));
INSERT INTO t1 VALUES($one);
ANALYZE;
}
set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
reset_db
execsql {
CREATE TABLE t1(a, UNIQUE(a));
INSERT INTO t1 VALUES($two);
ANALYZE;
}
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050}
} {1}
#-------------------------------------------------------------------------
# Test that stat4 data may be used with partial indexes.
#
do_test 17.1 {
reset_db
execsql {
CREATE TABLE t1(a, b, c, d);
CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL;
INSERT INTO t1 VALUES(-1, -1, -1, NULL);
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
}
for {set i 0} {$i < 32} {incr i} {
if {$i<8} {set b 0} else { set b $i }
execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') }
}
execsql {ANALYZE main.t1}
} {}
do_catchsql_test 17.1.2 {
ANALYZE temp.t1;
} {1 {no such table: temp.t1}}
do_eqp_test 17.2 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
} {/USING INDEX i1/}
do_eqp_test 17.3 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
} {/USING INDEX i1/}
do_execsql_test 17.4 {
CREATE INDEX i2 ON t1(c);
ANALYZE main.i2;
}
do_eqp_test 17.5 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
} {/USING INDEX i1/}
do_eqp_test 17.6 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
} {/USING INDEX i2/}
#-------------------------------------------------------------------------
#
do_test 18.1 {
reset_db
execsql {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
}
for {set i 0} {$i < 9} {incr i} {
execsql {
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
}
}
execsql ANALYZE
execsql { SELECT count(*) FROM sqlite_stat4 }
} {9}
#-------------------------------------------------------------------------
# For coverage.
#
ifcapable view {
do_test 19.1 {
reset_db
execsql {
CREATE TABLE t1(x, y);
CREATE INDEX i1 ON t1(x, y);
CREATE VIEW v1 AS SELECT * FROM t1;
ANALYZE;
}
} {}
}
ifcapable auth {
proc authproc {op args} {
if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" }
return "SQLITE_OK"
}
do_test 19.2 {
reset_db
db auth authproc
execsql {
CREATE TABLE t1(x, y);
CREATE VIEW v1 AS SELECT * FROM t1;
}
catchsql ANALYZE
} {1 {not authorized}}
}
#-------------------------------------------------------------------------
#
reset_db
proc r {args} { expr rand() }
db func r r
db func lrange lrange
do_test 20.1 {
execsql {
CREATE TABLE t1(a,b,c,d);
CREATE INDEX i1 ON t1(a,b,c,d);
}
for {set i 0} {$i < 16} {incr i} {
execsql {
INSERT INTO t1 VALUES($i, r(), r(), r());
INSERT INTO t1 VALUES($i, $i, r(), r());
INSERT INTO t1 VALUES($i, $i, $i, r());
INSERT INTO t1 VALUES($i, $i, $i, $i);
INSERT INTO t1 VALUES($i, $i, $i, $i);
INSERT INTO t1 VALUES($i, $i, $i, r());
INSERT INTO t1 VALUES($i, $i, r(), r());
INSERT INTO t1 VALUES($i, r(), r(), r());
}
}
} {}
do_execsql_test 20.2 { ANALYZE }
for {set i 0} {$i<16} {incr i} {
set val "$i $i $i $i"
do_execsql_test 20.3.$i {
SELECT count(*) FROM sqlite_stat4
WHERE lrange(test_decode(sample), 0, 3)=$val
} {1}
}
finish_test
+167
View File
@@ -0,0 +1,167 @@
# 2013 August 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains automated tests used to verify that the current build
# (which must be either ENABLE_STAT3 or ENABLE_STAT4) works with both stat3
# and stat4 data.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix analyzeA
ifcapable !stat4&&!stat3 {
finish_test
return
}
# Populate the stat3 table according to the current contents of the db
#
proc populate_stat3 {{bDropTable 1}} {
# Open a second connection on database "test.db" and run ANALYZE. If this
# is an ENABLE_STAT3 build, this is all that is required to create and
# populate the sqlite_stat3 table.
#
sqlite3 db2 test.db
execsql { ANALYZE }
# Now, if this is an ENABLE_STAT4 build, create and populate the
# sqlite_stat3 table based on the stat4 data gathered by the ANALYZE
# above. Then drop the sqlite_stat4 table.
#
ifcapable stat4 {
db2 func lindex lindex
execsql {
PRAGMA writable_schema = on;
CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);
INSERT INTO sqlite_stat3
SELECT DISTINCT tbl, idx,
lindex(neq,0), lindex(nlt,0), lindex(ndlt,0), test_extract(sample, 0)
FROM sqlite_stat4;
} db2
if {$bDropTable} { execsql {DROP TABLE sqlite_stat4} db2 }
execsql { PRAGMA writable_schema = off }
}
# Modify the database schema cookie to ensure that the other connection
# reloads the schema.
#
execsql {
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
# Populate the stat4 table according to the current contents of the db
#
proc populate_stat4 {{bDropTable 1}} {
sqlite3 db2 test.db
execsql { ANALYZE }
ifcapable stat3 {
execsql {
PRAGMA writable_schema = on;
CREATE TABLE sqlite_stat4(tbl,idx,neq,nlt,ndlt,sample);
INSERT INTO sqlite_stat4
SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample)
FROM sqlite_stat3;
} db2
if {$bDropTable} { execsql {DROP TABLE sqlite_stat3} db2 }
execsql { PRAGMA writable_schema = off }
}
# Modify the database schema cookie to ensure that the other connection
# reloads the schema.
#
execsql {
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
# Populate the stat4 table according to the current contents of the db.
# Leave deceptive data in the stat3 table. This data should be ignored
# in favour of that from the stat4 table.
#
proc populate_both {} {
ifcapable stat4 { populate_stat3 0 }
ifcapable stat3 { populate_stat4 0 }
sqlite3 db2 test.db
execsql {
PRAGMA writable_schema = on;
UPDATE sqlite_stat3 SET idx =
CASE idx WHEN 't1b' THEN 't1c' ELSE 't1b'
END;
PRAGMA writable_schema = off;
CREATE TABLE obscure_tbl_nm(x);
DROP TABLE obscure_tbl_nm;
} db2
db2 close
}
foreach {tn analyze_cmd} {
1 populate_stat4
2 populate_stat3
3 populate_both
} {
reset_db
do_test 1.$tn.1 {
execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c) }
for {set i 0} {$i < 100} {incr i} {
set c [expr int(pow(1.1,$i)/100)]
set b [expr 125 - int(pow(1.1,99-$i))/100]
execsql {INSERT INTO t1 VALUES($i, $b, $c)}
}
} {}
execsql { CREATE INDEX t1b ON t1(b) }
execsql { CREATE INDEX t1c ON t1(c) }
$analyze_cmd
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49
do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49
do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1
do_eqp_test 1.$tn.2.5 {
SELECT * FROM t1 WHERE b = 31 AND c = 0;
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}}
do_eqp_test 1.$tn.2.6 {
SELECT * FROM t1 WHERE b = 125 AND c = 16;
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}}
do_execsql_test 1.$tn.3.1 {
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
} {6}
do_execsql_test 1.$tn.3.2 {
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
} {90}
do_execsql_test 1.$tn.3.3 {
SELECT count(*) FROM t1 WHERE b BETWEEN 75 AND 125
} {90}
do_execsql_test 1.$tn.3.4 {
SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
} {6}
do_eqp_test 1.$tn.3.5 {
SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}}
do_eqp_test 1.$tn.3.6 {
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}}
}
finish_test
+683
View File
@@ -0,0 +1,683 @@
# 2013 August 3
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file contains automated tests used to verify that the sqlite_stat3
# functionality is working. The tests in this file are based on a subset
# of the sqlite_stat4 tests in analyze9.test.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix analyzeB
ifcapable !stat3 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE TABLE t1(a TEXT, b TEXT);
INSERT INTO t1 VALUES('(0)', '(0)');
INSERT INTO t1 VALUES('(1)', '(1)');
INSERT INTO t1 VALUES('(2)', '(2)');
INSERT INTO t1 VALUES('(3)', '(3)');
INSERT INTO t1 VALUES('(4)', '(4)');
CREATE INDEX i1 ON t1(a, b);
} {}
do_execsql_test 1.1 {
ANALYZE;
} {}
do_execsql_test 1.2 {
SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3;
} {
t1 i1 1 0 0 '(0)'
t1 i1 1 1 1 '(1)'
t1 i1 1 2 2 '(2)'
t1 i1 1 3 3 '(3)'
t1 i1 1 4 4 '(4)'
}
if {[permutation] != "utf16"} {
do_execsql_test 1.3 {
SELECT tbl,idx,nEq,nLt,nDLt,quote(sample) FROM sqlite_stat3;
} {
t1 i1 1 0 0 '(0)'
t1 i1 1 1 1 '(1)'
t1 i1 1 2 2 '(2)'
t1 i1 1 3 3 '(3)'
t1 i1 1 4 4 '(4)'
}
}
#-------------------------------------------------------------------------
# This is really just to test SQL user function "test_decode".
#
reset_db
do_execsql_test 2.1 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1(a) VALUES('some text');
INSERT INTO t1(a) VALUES(14);
INSERT INTO t1(a) VALUES(NULL);
INSERT INTO t1(a) VALUES(22.0);
INSERT INTO t1(a) VALUES(x'656667');
CREATE INDEX i1 ON t1(a, b, c);
ANALYZE;
SELECT quote(sample) FROM sqlite_stat3;
} {
NULL 14 22.0 {'some text'} X'656667'
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 3.1 {
CREATE TABLE t2(a, b);
CREATE INDEX i2 ON t2(a, b);
BEGIN;
}
do_test 3.2 {
for {set i 0} {$i < 1000} {incr i} {
set a [expr $i / 10]
set b [expr int(rand() * 15.0)]
execsql { INSERT INTO t2 VALUES($a, $b) }
}
execsql COMMIT
} {}
db func lindex lindex
# Each value of "a" occurs exactly 10 times in the table.
#
do_execsql_test 3.3.1 {
SELECT count(*) FROM t2 GROUP BY a;
} [lrange [string repeat "10 " 100] 0 99]
# The first element in the "nEq" list of all samples should therefore be 10.
#
do_execsql_test 3.3.2 {
ANALYZE;
SELECT nEq FROM sqlite_stat3;
} [lrange [string repeat "10 " 100] 0 23]
#-------------------------------------------------------------------------
#
do_execsql_test 3.4 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
INSERT INTO t1 VALUES(1, 1, 'one-a');
INSERT INTO t1 VALUES(11, 1, 'one-b');
INSERT INTO t1 VALUES(21, 1, 'one-c');
INSERT INTO t1 VALUES(31, 1, 'one-d');
INSERT INTO t1 VALUES(41, 1, 'one-e');
INSERT INTO t1 VALUES(51, 1, 'one-f');
INSERT INTO t1 VALUES(61, 1, 'one-g');
INSERT INTO t1 VALUES(71, 1, 'one-h');
INSERT INTO t1 VALUES(81, 1, 'one-i');
INSERT INTO t1 VALUES(91, 1, 'one-j');
INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
CREATE INDEX t1b ON t1(b);
ANALYZE;
SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
} {three-d three-e three-f}
#-------------------------------------------------------------------------
# These tests verify that the sample selection for stat3 appears to be
# working as designed.
#
reset_db
db func lindex lindex
db func lrange lrange
do_execsql_test 4.0 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(c, b, a);
}
proc insert_filler_rows_n {iStart args} {
set A(-ncopy) 1
set A(-nval) 1
foreach {k v} $args {
if {[info exists A($k)]==0} { error "no such option: $k" }
set A($k) $v
}
if {[llength $args] % 2} {
error "option requires an argument: [lindex $args end]"
}
for {set i 0} {$i < $A(-nval)} {incr i} {
set iVal [expr $iStart+$i]
for {set j 0} {$j < $A(-ncopy)} {incr j} {
execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
}
}
}
do_test 4.1 {
execsql { BEGIN }
insert_filler_rows_n 0 -ncopy 10 -nval 19
insert_filler_rows_n 20 -ncopy 1 -nval 100
execsql {
INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
ANALYZE;
SELECT count(*) FROM sqlite_stat3;
SELECT count(*) FROM t1;
}
} {24 297}
do_execsql_test 4.2 {
SELECT neq, nlt, ndlt, sample FROM sqlite_stat3 ORDER BY rowid LIMIT 16;
} {
10 0 0 0
10 10 1 1
10 20 2 2
10 30 3 3
10 40 4 4
10 50 5 5
10 60 6 6
10 70 7 7
10 80 8 8
10 90 9 9
10 100 10 10
10 110 11 11
10 120 12 12
10 130 13 13
10 140 14 14
10 150 15 15
}
do_execsql_test 4.3 {
SELECT neq, nlt, ndlt, sample FROM sqlite_stat3
ORDER BY rowid DESC LIMIT 2;
} {
2 295 120 201
5 290 119 200
}
do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
reset_db
do_test 4.7 {
execsql {
BEGIN;
CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
CREATE INDEX i1 ON t1(o);
}
for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
execsql { INSERT INTO t1 VALUES('x', $i) }
}
execsql {
COMMIT;
ANALYZE;
SELECT count(*) FROM sqlite_stat3;
}
} {1}
do_execsql_test 4.8 {
SELECT sample FROM sqlite_stat3;
} {x}
#-------------------------------------------------------------------------
# The following would cause a crash at one point.
#
reset_db
do_execsql_test 5.1 {
PRAGMA encoding = 'utf-16';
CREATE TABLE t0(v);
ANALYZE;
}
#-------------------------------------------------------------------------
# This was also crashing (corrupt sqlite_stat3 table).
#
reset_db
do_execsql_test 6.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
PRAGMA writable_schema = 1;
CREATE TEMP TABLE x1 AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3
ORDER BY (rowid%5), rowid;
DELETE FROM sqlite_stat3;
INSERT INTO sqlite_stat3 SELECT * FROM x1;
PRAGMA writable_schema = 0;
ANALYZE sqlite_master;
}
do_execsql_test 6.2 {
SELECT * FROM t1 WHERE a = 'abc';
}
#-------------------------------------------------------------------------
# The following tests experiment with adding corrupted records to the
# 'sample' column of the sqlite_stat3 table.
#
reset_db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test 7.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES(1, 1);
INSERT INTO t1 VALUES(2, 2);
INSERT INTO t1 VALUES(3, 3);
INSERT INTO t1 VALUES(4, 4);
INSERT INTO t1 VALUES(5, 5);
ANALYZE;
UPDATE sqlite_stat3 SET sample = X'' WHERE rowid = 1;
ANALYZE sqlite_master;
}
do_execsql_test 7.2 {
UPDATE sqlite_stat3 SET sample = X'FFFF';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.3 {
ANALYZE;
UPDATE sqlite_stat3 SET neq = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 1;
} {1 1}
do_execsql_test 7.4 {
ANALYZE;
UPDATE sqlite_stat3 SET ndlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 3;
} {3 3}
do_execsql_test 7.5 {
ANALYZE;
UPDATE sqlite_stat3 SET nlt = '0 0 0';
ANALYZE sqlite_master;
SELECT * FROM t1 WHERE a = 5;
} {5 5}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
CREATE TABLE t1(x TEXT);
CREATE INDEX i1 ON t1(x);
INSERT INTO t1 VALUES('1');
INSERT INTO t1 VALUES('2');
INSERT INTO t1 VALUES('3');
INSERT INTO t1 VALUES('4');
ANALYZE;
}
do_execsql_test 8.2 {
SELECT * FROM t1 WHERE x = 3;
} {3}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 9.1 {
CREATE TABLE t1(a, b, c, d, e);
CREATE INDEX i1 ON t1(a, b, c, d);
CREATE INDEX i2 ON t1(e);
}
do_test 9.2 {
execsql BEGIN;
for {set i 0} {$i < 100} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
for {set i 0} {$i < 20} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
}
for {set i 102} {$i < 200} {incr i} {
execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
}
execsql COMMIT
execsql ANALYZE
} {}
do_eqp_test 9.3.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
} {/t1 USING INDEX i1/}
do_eqp_test 9.3.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
} {/t1 USING INDEX i1/}
set value_d [expr 101]
do_eqp_test 9.4.1 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i1/}
set value_d [expr 99]
do_eqp_test 9.4.2 {
SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
} {/t1 USING INDEX i1/}
#-------------------------------------------------------------------------
# Check that the planner takes stat3 data into account when considering
# "IS NULL" and "IS NOT NULL" constraints.
#
do_execsql_test 10.1.1 {
DROP TABLE IF EXISTS t3;
CREATE TABLE t3(a, b);
CREATE INDEX t3a ON t3(a);
CREATE INDEX t3b ON t3(b);
}
do_test 10.1.2 {
for {set i 1} {$i < 100} {incr i} {
if {$i>90} { set a $i } else { set a NULL }
set b [expr $i % 5]
execsql "INSERT INTO t3 VALUES($a, $b)"
}
execsql ANALYZE
} {}
do_eqp_test 10.1.3 {
SELECT * FROM t3 WHERE a IS NULL AND b = 2
} {/t3 USING INDEX t3b/}
do_eqp_test 10.1.4 {
SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2
} {/t3 USING INDEX t3a/}
#-------------------------------------------------------------------------
# Check that stat3 data is used correctly with non-default collation
# sequences.
#
foreach {tn schema} {
1 {
CREATE TABLE t4(a COLLATE nocase, b);
CREATE INDEX t4a ON t4(a);
CREATE INDEX t4b ON t4(b);
}
2 {
CREATE TABLE t4(a, b);
CREATE INDEX t4a ON t4(a COLLATE nocase);
CREATE INDEX t4b ON t4(b);
}
} {
drop_all_tables
do_test 11.$tn.1 { execsql $schema } {}
do_test 11.$tn.2 {
for {set i 0} {$i < 100} {incr i} {
if { ($i % 10)==0 } { set a ABC } else { set a DEF }
set b [expr $i % 5]
execsql { INSERT INTO t4 VALUES($a, $b) }
}
execsql ANALYZE
} {}
do_eqp_test 11.$tn.3 {
SELECT * FROM t4 WHERE a = 'def' AND b = 3;
} {/t4 USING INDEX t4b/}
if {$tn==1} {
set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;"
do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/}
} else {
set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;"
do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/}
set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;"
do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/}
}
}
#-------------------------------------------------------------------------
# Test that nothing untoward happens if the stat3 table contains entries
# for indexes that do not exist. Or NULL values in the idx column.
# Or NULL values in any of the other columns.
#
drop_all_tables
do_execsql_test 15.1 {
CREATE TABLE x1(a, b, UNIQUE(a, b));
INSERT INTO x1 VALUES(1, 2);
INSERT INTO x1 VALUES(3, 4);
INSERT INTO x1 VALUES(5, 6);
ANALYZE;
INSERT INTO sqlite_stat3 VALUES(NULL, NULL, NULL, NULL, NULL, NULL);
}
db close
sqlite3 db test.db
do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.3 {
INSERT INTO sqlite_stat3 VALUES(42, 42, 42, 42, 42, 42);
}
db close
sqlite3 db test.db
do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.5 {
UPDATE sqlite_stat1 SET stat = NULL;
}
db close
sqlite3 db test.db
do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.7 {
ANALYZE;
UPDATE sqlite_stat1 SET tbl = 'no such tbl';
}
db close
sqlite3 db test.db
do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6}
do_execsql_test 15.9 {
ANALYZE;
UPDATE sqlite_stat3 SET neq = NULL, nlt=NULL, ndlt=NULL;
}
db close
sqlite3 db test.db
do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6}
# This is just for coverage....
do_execsql_test 15.11 {
ANALYZE;
UPDATE sqlite_stat1 SET stat = stat || ' unordered';
}
db close
sqlite3 db test.db
do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6}
#-------------------------------------------------------------------------
# Test that allocations used for sqlite_stat3 samples are included in
# the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED.
#
set one [string repeat x 1000]
set two [string repeat x 2000]
do_test 16.1 {
reset_db
execsql {
CREATE TABLE t1(a, UNIQUE(a));
INSERT INTO t1 VALUES($one);
ANALYZE;
}
set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
reset_db
execsql {
CREATE TABLE t1(a, UNIQUE(a));
INSERT INTO t1 VALUES($two);
ANALYZE;
}
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
expr {$nByte2 > $nByte+950 && $nByte2 < $nByte+1050}
} {1}
#-------------------------------------------------------------------------
# Test that stat3 data may be used with partial indexes.
#
do_test 17.1 {
reset_db
execsql {
CREATE TABLE t1(a, b, c, d);
CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL;
INSERT INTO t1 VALUES(-1, -1, -1, NULL);
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
}
for {set i 0} {$i < 32} {incr i} {
execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') }
}
execsql {ANALYZE main.t1}
} {}
do_catchsql_test 17.1.2 {
ANALYZE temp.t1;
} {1 {no such table: temp.t1}}
do_eqp_test 17.2 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
} {/USING INDEX i1/}
do_eqp_test 17.3 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
} {/USING INDEX i1/}
do_execsql_test 17.4 {
CREATE INDEX i2 ON t1(c) WHERE d IS NOT NULL;
ANALYZE main.i2;
}
do_eqp_test 17.5 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0;
} {/USING INDEX i1/}
do_eqp_test 17.6 {
SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
} {/USING INDEX i2/}
#-------------------------------------------------------------------------
#
do_test 18.1 {
reset_db
execsql {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
}
for {set i 0} {$i < 9} {incr i} {
execsql {
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
INSERT INTO t1 VALUES($i, 0);
}
}
execsql ANALYZE
execsql { SELECT count(*) FROM sqlite_stat3 }
} {9}
#-------------------------------------------------------------------------
# For coverage.
#
ifcapable view {
do_test 19.1 {
reset_db
execsql {
CREATE TABLE t1(x, y);
CREATE INDEX i1 ON t1(x, y);
CREATE VIEW v1 AS SELECT * FROM t1;
ANALYZE;
}
} {}
}
ifcapable auth {
proc authproc {op args} {
if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" }
return "SQLITE_OK"
}
do_test 19.2 {
reset_db
db auth authproc
execsql {
CREATE TABLE t1(x, y);
CREATE VIEW v1 AS SELECT * FROM t1;
}
catchsql ANALYZE
} {1 {not authorized}}
}
#-------------------------------------------------------------------------
#
reset_db
proc r {args} { expr rand() }
db func r r
db func lrange lrange
do_test 20.1 {
execsql {
CREATE TABLE t1(a,b,c,d);
CREATE INDEX i1 ON t1(a,b,c,d);
}
for {set i 0} {$i < 16} {incr i} {
execsql {
INSERT INTO t1 VALUES($i, r(), r(), r());
INSERT INTO t1 VALUES($i, $i, r(), r());
INSERT INTO t1 VALUES($i, $i, $i, r());
INSERT INTO t1 VALUES($i, $i, $i, $i);
INSERT INTO t1 VALUES($i, $i, $i, $i);
INSERT INTO t1 VALUES($i, $i, $i, r());
INSERT INTO t1 VALUES($i, $i, r(), r());
INSERT INTO t1 VALUES($i, r(), r(), r());
}
}
} {}
do_execsql_test 20.2 { ANALYZE }
for {set i 0} {$i<16} {incr i} {
set val $i
do_execsql_test 20.3.$i {
SELECT count(*) FROM sqlite_stat3 WHERE sample=$val
} {1}
}
finish_test
+8 -4
View File
@@ -2325,10 +2325,14 @@ ifcapable compound&&subquery {
}
}
}
ifcapable stat3 {
set stat3 "sqlite_stat3 "
ifcapable stat4 {
set stat4 "sqlite_stat4 "
} else {
set stat3 ""
ifcapable stat3 {
set stat4 "sqlite_stat3 "
} else {
set stat4 ""
}
}
do_test auth-5.2 {
execsql {
@@ -2337,7 +2341,7 @@ ifcapable compound&&subquery {
WHERE type='table'
ORDER BY name
}
} "sqlite_stat1 ${stat3}t1 t2 t3 t4"
} "sqlite_stat1 ${stat4}t1 t2 t3 t4"
}
# Ticket #3944
+2 -2
View File
@@ -61,7 +61,7 @@ proc lookaside {db} {
}
}
ifcapable stat3 {
ifcapable stat4||stat3 {
set STAT3 1
} else {
set STAT3 0
@@ -214,7 +214,7 @@ foreach ::lookaside_buffer_size {0 64 120} {
# much greater than just that reported by DBSTATUS_SCHEMA_USED in this
# case.
#
# Some of the memory used for sqlite_stat3 is unaccounted for by
# Some of the memory used for sqlite_stat4 is unaccounted for by
# dbstatus.
#
# Finally, on osx the estimate of memory used by the schema may be
+54
View File
@@ -0,0 +1,54 @@
# 2001 September 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for foreign keys.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fkey7
ifcapable {!foreignkey} {
finish_test
return
}
do_execsql_test 1.1 {
PRAGMA foreign_keys = 1;
CREATE TABLE s1(a PRIMARY KEY, b);
CREATE TABLE par(a, b REFERENCES s1, c UNIQUE, PRIMARY KEY(a));
CREATE TABLE c1(a, b REFERENCES par);
CREATE TABLE c2(a, b REFERENCES par);
CREATE TABLE c3(a, b REFERENCES par(c));
}
proc auth {op tbl args} {
if {$op == "SQLITE_READ"} { set ::tbls($tbl) 1 }
return "SQLITE_OK"
}
db auth auth
db cache size 0
proc do_tblsread_test {tn sql tbllist} {
array unset ::tbls
uplevel [list execsql $sql]
uplevel [list do_test $tn {lsort [array names ::tbls]} $tbllist]
}
do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1}
do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par}
do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par}
do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1}
finish_test
+35
View File
@@ -402,5 +402,40 @@ foreach {tn1 c} {
}
}
#-------------------------------------------------------------------------
# Cursory test of remove_diacritics=0.
#
# 00C4;LATIN CAPITAL LETTER A WITH DIAERESIS
# 00D6;LATIN CAPITAL LETTER O WITH DIAERESIS
# 00E4;LATIN SMALL LETTER A WITH DIAERESIS
# 00F6;LATIN SMALL LETTER O WITH DIAERESIS
#
do_execsql_test 8.1.1 "
CREATE VIRTUAL TABLE t3 USING fts4(tokenize=unicode61 'remove_diacritics=1');
INSERT INTO t3 VALUES('o');
INSERT INTO t3 VALUES('a');
INSERT INTO t3 VALUES('O');
INSERT INTO t3 VALUES('A');
INSERT INTO t3 VALUES('\xD6');
INSERT INTO t3 VALUES('\xC4');
INSERT INTO t3 VALUES('\xF6');
INSERT INTO t3 VALUES('\xE4');
"
do_execsql_test 8.1.2 {
SELECT rowid FROM t3 WHERE t3 MATCH 'o';
} {1 3 5 7}
do_execsql_test 8.1.3 {
SELECT rowid FROM t3 WHERE t3 MATCH 'a';
} {2 4 6 8}
do_execsql_test 8.2.1 {
CREATE VIRTUAL TABLE t4 USING fts4(tokenize=unicode61 "remove_diacritics=0");
INSERT INTO t4 SELECT * FROM t3;
}
do_execsql_test 8.2.2 {
SELECT rowid FROM t4 WHERE t4 MATCH 'o';
} {1 3}
do_execsql_test 8.2.3 {
SELECT rowid FROM t4 WHERE t4 MATCH 'a';
} {2 4}
finish_test
+3 -3
View File
@@ -149,15 +149,15 @@ do_test index6-2.2 {
SELECT * FROM t2 WHERE a=5;
}
} {/.* TABLE t2 USING INDEX t2a1 .*/}
ifcapable stat3 {
do_test index6-2.3stat3 {
ifcapable stat4||stat3 {
do_test index6-2.3stat4 {
execsql {
EXPLAIN QUERY PLAN
SELECT * FROM t2 WHERE a IS NOT NULL;
}
} {/.* TABLE t2 USING INDEX t2a1 .*/}
} else {
do_test index6-2.3stat3 {
do_test index6-2.3stat4 {
execsql {
EXPLAIN QUERY PLAN
SELECT * FROM t2 WHERE a IS NOT NULL AND a>0;
+49 -1
View File
@@ -15,6 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix mallocA
# Only run these tests if memory debugging is turned on.
#
@@ -40,7 +41,6 @@ db eval {
db close
copy_file test.db test.db.bu
do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody {
ANALYZE
}
@@ -53,6 +53,7 @@ do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody {
do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody {
ANALYZE main.t1
}
ifcapable reindex {
do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody {
REINDEX;
@@ -68,6 +69,53 @@ ifcapable reindex {
}
}
reset_db
sqlite3_db_config_lookaside db 0 0 0
do_execsql_test 6-prep {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a, b);
INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1
INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2
INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3
INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4
INSERT INTO t1 VALUES('def', 'w'); -- rowid=5
INSERT INTO t1 VALUES('def', 'x'); -- rowid=6
INSERT INTO t1 VALUES('def', 'y'); -- rowid=7
INSERT INTO t1 VALUES('def', 'z'); -- rowid=8
ANALYZE;
}
do_faultsim_test 6.1 -faults oom* -body {
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' }
} -test {
faultsim_test_result [list 0 2]
}
do_faultsim_test 6.2 -faults oom* -body {
execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' }
} -test {
faultsim_test_result [list 0 {1 2}]
}
ifcapable stat3 {
do_test 6.3-prep {
execsql {
PRAGMA writable_schema = 1;
CREATE TABLE sqlite_stat4 AS
SELECT tbl, idx, neq, nlt, ndlt, sqlite_record(sample) AS sample
FROM sqlite_stat3;
}
} {}
do_faultsim_test 6.3 -faults oom* -body {
execsql {
ANALYZE sqlite_master;
SELECT rowid FROM t1 WHERE a='abc' AND b<'y';
}
} -test {
faultsim_test_result [list 0 {1 2}]
}
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}
+10
View File
@@ -311,6 +311,14 @@ test_suite "coverage-pager" -description {
walfault.test walbak.test journal2.test tkt-9d68c883.test
}
test_suite "coverage-analyze" -description {
Coverage tests for file analyze.c.
} -files {
analyze3.test analyze4.test analyze5.test analyze6.test
analyze7.test analyze8.test analyze9.test analyzeA.test
analyze.test analyzeB.test mallocA.test
}
lappend ::testsuitelist xxx
#-------------------------------------------------------------------------
@@ -500,6 +508,8 @@ test_suite "utf16" -description {
pragma encoding = 'UTF-16'
} -files {
alter.test alter3.test
analyze.test analyze3.test analyze4.test analyze5.test analyze6.test
analyze7.test analyze8.test analyze9.test analyzeA.test analyzeB.test
auth.test bind.test blob.test capi2.test capi3.test collate1.test
collate2.test collate3.test collate4.test collate5.test collate6.test
conflict.test date.test delete.test expr.test fkey1.test func.test
+12
View File
@@ -722,7 +722,11 @@ do_test shell1-3-31.1 {
# Test the output of the ".dump" command
#
do_test shell1-4.1 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA encoding=UTF16;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
}
@@ -752,6 +756,14 @@ INSERT INTO t1 VALUES(X'807f');}}
# Test the output of ".mode tcl"
#
do_test shell1-4.3 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
PRAGMA encoding=UTF8;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(null), (''), (1), (2.25), ('hello'), (x'807f');
}
catchcmd test.db ".mode tcl\nselect * from t1;"
} {0 {""
""
+26
View File
@@ -242,4 +242,30 @@ SELECT * FROM t1;}
5,"this is 5"}}
}
# Import columns containing quoted strings
do_test shell5-1.9 {
set out [open shell5.csv w]
puts $out {1,"",11}
puts $out {2,"x",22}
puts $out {3,"""",33}
puts $out {4,"hello",44}
puts $out "5,55,\"\"\r"
puts $out {6,66,"x"}
puts $out {7,77,""""}
puts $out {8,88,"hello"}
puts $out {"",9,99}
puts $out {"x",10,110}
puts $out {"""",11,121}
puts $out {"hello",12,132}
close $out
file delete -force test.db
catchcmd test.db {.mode csv
CREATE TABLE t1(a,b,c);
.import shell5.csv t1
}
sqlite3 db test.db
db eval {SELECT *, '|' FROM t1 ORDER BY rowid}
} {1 {} 11 | 2 x 22 | 3 {"} 33 | 4 hello 44 | 5 55 {} | 6 66 x | 7 77 {"} | 8 88 hello | {} 9 99 | x 10 110 | {"} 11 121 | hello 12 132 |}
db close
finish_test
+1
View File
@@ -268,6 +268,7 @@ do_test table-5.2.1 {
DROP TABLE IF EXISTS sqlite_stat1;
DROP TABLE IF EXISTS sqlite_stat2;
DROP TABLE IF EXISTS sqlite_stat3;
DROP TABLE IF EXISTS sqlite_stat4;
SELECT name FROM sqlite_master WHERE name GLOB 'sqlite_stat*';
}
} {}
+104 -34
View File
@@ -14,7 +14,7 @@
# $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $
#-------------------------------------------------------------------------
# The commands provided by the code in this file to help with creating
# The commands provided by the code in this file to help with creating
# test cases are as follows:
#
# Commands to manipulate the db and the file-system at a high level:
@@ -42,6 +42,7 @@
#
# Commands to execute/explain SQL statements:
#
# memdbsql SQL
# stepsql DB SQL
# execsql2 SQL
# explain_no_trace SQL
@@ -80,7 +81,7 @@
# presql
#
# Set the precision of FP arithmatic used by the interpreter. And
# Set the precision of FP arithmatic used by the interpreter. And
# configure SQLite to take database file locks on the page that begins
# 64KB into the database file instead of the one 1GB in. This means
# the code that handles that special case can be tested without creating
@@ -90,7 +91,7 @@ set tcl_precision 15
sqlite3_test_control_pending_byte 0x0010000
# If the pager codec is available, create a wrapper for the [sqlite3]
# If the pager codec is available, create a wrapper for the [sqlite3]
# command that appends "-key {xyzzy}" to the command line. i.e. this:
#
# sqlite3 db test.db
@@ -122,7 +123,7 @@ if {[info command sqlite_orig]==""} {
}
set res
} else {
# This command is not opening a new database connection. Pass the
# This command is not opening a new database connection. Pass the
# arguments through to the C implementation as the are.
#
uplevel 1 sqlite_orig $args
@@ -291,6 +292,66 @@ proc do_delete_file {force args} {
}
}
if {$::tcl_platform(platform) eq "windows"} {
proc do_remove_win32_dir {args} {
set nRetry [getFileRetries] ;# Maximum number of retries.
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
foreach dirName $args {
# On windows, sometimes even a [remove_win32_dir] can fail just after
# a directory is emptied. The cause is usually "tag-alongs" - programs
# like anti-virus software, automatic backup tools and various explorer
# extensions that keep a file open a little longer than we expect,
# causing the delete to fail.
#
# The solution is to wait a short amount of time before retrying the
# removal.
#
if {$nRetry > 0} {
for {set i 0} {$i < $nRetry} {incr i} {
set rc [catch {
remove_win32_dir $dirName
} msg]
if {$rc == 0} break
if {$nDelay > 0} { after $nDelay }
}
if {$rc} { error $msg }
} else {
remove_win32_dir $dirName
}
}
}
proc do_delete_win32_file {args} {
set nRetry [getFileRetries] ;# Maximum number of retries.
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
foreach fileName $args {
# On windows, sometimes even a [delete_win32_file] can fail just after
# a file is closed. The cause is usually "tag-alongs" - programs like
# anti-virus software, automatic backup tools and various explorer
# extensions that keep a file open a little longer than we expect,
# causing the delete to fail.
#
# The solution is to wait a short amount of time before retrying the
# delete.
#
if {$nRetry > 0} {
for {set i 0} {$i < $nRetry} {incr i} {
set rc [catch {
delete_win32_file $fileName
} msg]
if {$rc == 0} break
if {$nDelay > 0} { after $nDelay }
}
if {$rc} { error $msg }
} else {
delete_win32_file $fileName
}
}
}
}
proc execpresql {handle args} {
trace remove execution $handle enter [list execpresql $handle]
if {[info exists ::G(perm:presql)]} {
@@ -312,8 +373,8 @@ proc do_not_use_codec {} {
#
if {[info exists cmdlinearg]==0} {
# Parse any options specified in the $argv array. This script accepts the
# following options:
# Parse any options specified in the $argv array. This script accepts the
# following options:
#
# --pause
# --soft-heap-limit=NN
@@ -342,7 +403,7 @@ if {[info exists cmdlinearg]==0} {
foreach a $argv {
switch -regexp -- $a {
{^-+pause$} {
# Wait for user input before continuing. This is to give the user an
# Wait for user input before continuing. This is to give the user an
# opportunity to connect profiling tools to the process.
puts -nonewline "Press RETURN to begin..."
flush stdout
@@ -405,8 +466,8 @@ if {[info exists cmdlinearg]==0} {
# Install the malloc layer used to inject OOM errors. And the 'automatic'
# extensions. This only needs to be done once for the process.
#
sqlite3_shutdown
install_malloc_faultsim 1
sqlite3_shutdown
install_malloc_faultsim 1
sqlite3_initialize
autoinstall_test_functions
@@ -516,7 +577,7 @@ proc incr_ntest {} {
}
# Invoke the do_test procedure to run a single test
# Invoke the do_test procedure to run a single test
#
proc do_test {name cmd expected} {
global argv cmdlinearg
@@ -525,7 +586,7 @@ proc do_test {name cmd expected} {
sqlite3_memdebug_settitle $name
# if {[llength $argv]==0} {
# if {[llength $argv]==0} {
# set go 1
# } else {
# set go 0
@@ -628,13 +689,13 @@ proc do_realnum_test {name cmd expected} {
proc fix_testname {varname} {
upvar $varname testname
if {[info exists ::testprefix]
if {[info exists ::testprefix]
&& [string is digit [string range $testname 0 0]]
} {
set testname "${::testprefix}-$testname"
}
}
proc do_execsql_test {testname sql {result {}}} {
fix_testname testname
uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
@@ -720,7 +781,7 @@ proc delete_all_data {} {
}
}
# Run an SQL script.
# Run an SQL script.
# Return the number of microseconds per statement.
#
proc speed_trial {name numstmt units sql} {
@@ -984,6 +1045,15 @@ proc execsql2 {sql} {
return $result
}
# Use a temporary in-memory database to execute SQL statements
#
proc memdbsql {sql} {
sqlite3 memdb :memory:
set result [memdb eval $sql]
memdb close
return $result
}
# Use the non-callback API to execute multiple SQL statements
#
proc stepsql {dbptr sql} {
@@ -1098,7 +1168,7 @@ proc crashsql {args} {
set crashfile ""
set dc ""
set sql [lindex $args end]
for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
set z [lindex $args $ii]
set n [string length $z]
@@ -1117,7 +1187,7 @@ proc crashsql {args} {
error "Compulsory option -file missing"
}
# $crashfile gets compared to the native filename in
# $crashfile gets compared to the native filename in
# cfSync(), which can be different then what TCL uses by
# default, so here we force it to the "nativename" format.
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
@@ -1152,7 +1222,7 @@ proc crashsql {args} {
set r [catch {
exec [info nameofexec] crash.tcl >@stdout
} msg]
# Windows/ActiveState TCL returns a slightly different
# error message. We map that to the expected message
# so that we don't have to change all of the test
@@ -1162,7 +1232,7 @@ proc crashsql {args} {
set msg "child process exited abnormally"
}
}
lappend r $msg
}
@@ -1188,7 +1258,7 @@ proc run_ioerr_prep {} {
# Usage: do_ioerr_test <test number> <options...>
#
# This proc is used to implement test cases that check that IO errors
# are correctly handled. The first argument, <test number>, is an integer
# are correctly handled. The first argument, <test number>, is an integer
# used to name the tests executed by this proc. Options are as follows:
#
# -tclprep TCL script to run to prepare test.
@@ -1217,7 +1287,7 @@ proc do_ioerr_test {testname args} {
# TEMPORARY: For 3.5.9, disable testing of extended result codes. There are
# a couple of obscure IO errors that do not return them.
set ::ioerropts(-erc) 0
# Create a single TCL script from the TCL and SQL specified
# as the body of the test.
set ::ioerrorbody {}
@@ -1241,7 +1311,7 @@ proc do_ioerr_test {testname args} {
set ::TN $n
incr ::ioerropts(-count) -1
if {$::ioerropts(-count)<0} break
# Skip this IO error if it was specified with the "-exclude" option.
if {[info exists ::ioerropts(-exclude)]} {
if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue
@@ -1250,7 +1320,7 @@ proc do_ioerr_test {testname args} {
restore_prng_state
}
# Delete the files test.db and test2.db, then execute the TCL and
# Delete the files test.db and test2.db, then execute the TCL and
# SQL (in that order) to prepare for the test case.
do_test $testname.$n.1 {
run_ioerr_prep
@@ -1268,7 +1338,7 @@ proc do_ioerr_test {testname args} {
}] $n
# Execute the TCL script created for the body of this test. If
# at least N IO operations performed by SQLite as a result of
# at least N IO operations performed by SQLite as a result of
# the script, the Nth will fail.
do_test $testname.$n.3 {
set ::sqlite_io_error_hit 0
@@ -1322,12 +1392,12 @@ proc do_ioerr_test {testname args} {
set ::sqlite_io_error_hit 0
set ::sqlite_io_error_pending 0
# Check that no page references were leaked. There should be
# a single reference if there is still an active transaction,
# Check that no page references were leaked. There should be
# a single reference if there is still an active transaction,
# or zero otherwise.
#
# UPDATE: If the IO error occurs after a 'BEGIN' but before any
# locks are established on database files (i.e. if the error
# locks are established on database files (i.e. if the error
# occurs while attempting to detect a hot-journal file), then
# there may 0 page references and an active transaction according
# to [sqlite3_get_autocommit].
@@ -1343,7 +1413,7 @@ proc do_ioerr_test {testname args} {
} {1}
}
# If there is an open database handle and no open transaction,
# If there is an open database handle and no open transaction,
# and the pager is not running in exclusive-locking mode,
# check that the pager is in "unlocked" state. Theoretically,
# if a call to xUnlock() failed due to an IO error the underlying
@@ -1447,7 +1517,7 @@ proc allcksum {{db db}} {
}
# Generate a checksum based on the contents of a single database with
# a database connection. The name of the database is $dbname.
# a database connection. The name of the database is $dbname.
# Examples of $dbname are "temp" or "main".
#
proc dbcksum {db dbname} {
@@ -1541,8 +1611,8 @@ proc drop_all_tables {{db db}} {
#-------------------------------------------------------------------------
# If a test script is executed with global variable $::G(perm:name) set to
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
# in rollback mode. The following Tcl procs are used to make this less
# "wal", then the tests are run in WAL mode. Otherwise, they should be run
# in rollback mode. The following Tcl procs are used to make this less
# intrusive:
#
# wal_set_journal_mode ?DB?
@@ -1557,9 +1627,9 @@ proc drop_all_tables {{db db}} {
# Otherwise (if not running a WAL permutation) this is a no-op.
#
# wal_is_wal_mode
#
#
# Returns true if this test should be run in WAL mode. False otherwise.
#
#
proc wal_is_wal_mode {} {
expr {[permutation] eq "wal"}
}
@@ -1660,10 +1730,10 @@ proc slave_test_file {zFile} {
}
set ::sqlite_open_file_count 0
# Test that the global "shared-cache" setting was not altered by
# Test that the global "shared-cache" setting was not altered by
# the test script.
#
ifcapable shared_cache {
ifcapable shared_cache {
set res [expr {[sqlite3_enable_shared_cache] == $scs}]
do_test ${tail}-sharedcachesetting [list set {} $res] 1
}
+36 -9
View File
@@ -16,11 +16,26 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat3 {
ifcapable !stat4&&!stat3 {
finish_test
return
}
proc s {blob} {
set ret ""
binary scan $blob c* bytes
foreach b $bytes {
set t [binary format c $b]
if {[string is print $t]} {
append ret $t
} else {
append ret .
}
}
return $ret
}
db function s s
do_test tkt-cbd05-1.1 {
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT UNIQUE NOT NULL);
@@ -39,18 +54,30 @@ do_test tkt-cbd05-1.1 {
}
} {10}
do_test tkt-cbd05-1.2 {
db eval {
ANALYZE;
db eval { ANALYZE; }
ifcapable stat4 {
db eval {
PRAGMA writable_schema = 1;
CREATE VIEW vvv AS
SELECT tbl,idx,neq,nlt,ndlt,test_extract(sample,0) AS sample
FROM sqlite_stat4;
PRAGMA writable_schema = 0;
}
} else {
db eval {
CREATE VIEW vvv AS
SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat3;
}
}
} {}
do_test tkt-cbd05-1.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat3
SELECT tbl,idx,group_concat(s(sample),' ')
FROM vvv
WHERE idx = 't1_x'
GROUP BY tbl,idx
}
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
} {t1 t1_x { A B C D E F G H I}}
do_test tkt-cbd05-2.1 {
db eval {
@@ -77,11 +104,11 @@ do_test tkt-cbd05-2.2 {
} {}
do_test tkt-cbd05-2.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat3
SELECT tbl,idx,group_concat(s(sample),' ')
FROM vvv
WHERE idx = 't1_x'
GROUP BY tbl,idx
}
} {/t1 t1_x .[ ABCDEFGHI]{10}./}
} {t1 t1_x { A B C D E F G H I}}
finish_test
+187
View File
@@ -0,0 +1,187 @@
# 2013-09-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.
#
#***********************************************************************
#
# TPC-H test queries.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tpch01
do_execsql_test tpch01-1.0 {
CREATE TABLE NATION ( N_NATIONKEY INTEGER NOT NULL,
N_NAME CHAR(25) NOT NULL,
N_REGIONKEY INTEGER NOT NULL,
N_COMMENT VARCHAR(152));
CREATE TABLE REGION ( R_REGIONKEY INTEGER NOT NULL,
R_NAME CHAR(25) NOT NULL,
R_COMMENT VARCHAR(152));
CREATE TABLE PART ( P_PARTKEY INTEGER NOT NULL,
P_NAME VARCHAR(55) NOT NULL,
P_MFGR CHAR(25) NOT NULL,
P_BRAND CHAR(10) NOT NULL,
P_TYPE VARCHAR(25) NOT NULL,
P_SIZE INTEGER NOT NULL,
P_CONTAINER CHAR(10) NOT NULL,
P_RETAILPRICE DECIMAL(15,2) NOT NULL,
P_COMMENT VARCHAR(23) NOT NULL );
CREATE TABLE SUPPLIER ( S_SUPPKEY INTEGER NOT NULL,
S_NAME CHAR(25) NOT NULL,
S_ADDRESS VARCHAR(40) NOT NULL,
S_NATIONKEY INTEGER NOT NULL,
S_PHONE CHAR(15) NOT NULL,
S_ACCTBAL DECIMAL(15,2) NOT NULL,
S_COMMENT VARCHAR(101) NOT NULL);
CREATE TABLE PARTSUPP ( PS_PARTKEY INTEGER NOT NULL,
PS_SUPPKEY INTEGER NOT NULL,
PS_AVAILQTY INTEGER NOT NULL,
PS_SUPPLYCOST DECIMAL(15,2) NOT NULL,
PS_COMMENT VARCHAR(199) NOT NULL );
CREATE TABLE CUSTOMER ( C_CUSTKEY INTEGER NOT NULL,
C_NAME VARCHAR(25) NOT NULL,
C_ADDRESS VARCHAR(40) NOT NULL,
C_NATIONKEY INTEGER NOT NULL,
C_PHONE CHAR(15) NOT NULL,
C_ACCTBAL DECIMAL(15,2) NOT NULL,
C_MKTSEGMENT CHAR(10) NOT NULL,
C_COMMENT VARCHAR(117) NOT NULL);
CREATE TABLE ORDERS ( O_ORDERKEY INTEGER NOT NULL,
O_CUSTKEY INTEGER NOT NULL,
O_ORDERSTATUS CHAR(1) NOT NULL,
O_TOTALPRICE DECIMAL(15,2) NOT NULL,
O_ORDERDATE DATE NOT NULL,
O_ORDERPRIORITY CHAR(15) NOT NULL,
O_CLERK CHAR(15) NOT NULL,
O_SHIPPRIORITY INTEGER NOT NULL,
O_COMMENT VARCHAR(79) NOT NULL);
CREATE TABLE LINEITEM ( L_ORDERKEY INTEGER NOT NULL,
L_PARTKEY INTEGER NOT NULL,
L_SUPPKEY INTEGER NOT NULL,
L_LINENUMBER INTEGER NOT NULL,
L_QUANTITY DECIMAL(15,2) NOT NULL,
L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL,
L_DISCOUNT DECIMAL(15,2) NOT NULL,
L_TAX DECIMAL(15,2) NOT NULL,
L_RETURNFLAG CHAR(1) NOT NULL,
L_LINESTATUS CHAR(1) NOT NULL,
L_SHIPDATE DATE NOT NULL,
L_COMMITDATE DATE NOT NULL,
L_RECEIPTDATE DATE NOT NULL,
L_SHIPINSTRUCT CHAR(25) NOT NULL,
L_SHIPMODE CHAR(10) NOT NULL,
L_COMMENT VARCHAR(44) NOT NULL);
CREATE INDEX npki on nation(N_NATIONKEY);
CREATE INDEX rpki on region(R_REGIONKEY);
CREATE INDEX ppki on part(P_PARTKEY);
CREATE INDEX spki on supplier(S_SUPPKEY);
CREATE INDEX pspki on partsupp(PS_PARTKEY, PS_SUPPKEY);
CREATE INDEX cpki on customer(C_CUSTKEY);
CREATE INDEX opki on orders(O_ORDERKEY);
CREATE INDEX lpki on lineitem(L_ORDERKEY, L_LINENUMBER);
CREATE INDEX nrki on nation(n_regionkey);
CREATE INDEX snki on supplier(s_nationkey);
CREATE INDEX cnki on customer(c_nationkey);
CREATE INDEX ocki on orders(O_CUSTKEY);
CREATE INDEX odi on orders(O_ORDERDATE);
CREATE INDEX lpki2 on lineitem(L_PARTKEY);
CREATE INDEX lski on lineitem(L_SUPPKEY);
CREATE INDEX lsdi on lineitem(L_SHIPDATE);
CREATE INDEX lcdi on lineitem(L_COMMITDATE);
CREATE INDEX lrdi on lineitem(L_RECEIPTDATE);
CREATE INDEX bootleg_nni on nation(N_NAME);
CREATE INDEX bootleg_psi on part(p_size);
CREATE INDEX bootleg_pti on part(p_type);
ANALYZE sqlite_master;
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lrdi','600572 236');
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lcdi','600572 244');
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lsdi','600572 238');
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lski','600572 601');
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki2','600572 31');
INSERT INTO sqlite_stat1 VALUES('LINEITEM','lpki','600572 5 1');
INSERT INTO sqlite_stat1 VALUES('ORDERS','odi','150000 63');
INSERT INTO sqlite_stat1 VALUES('ORDERS','ocki','150000 15');
INSERT INTO sqlite_stat1 VALUES('ORDERS','opki','150000 1');
INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cnki','15000 600');
INSERT INTO sqlite_stat1 VALUES('CUSTOMER','cpki','15000 1');
INSERT INTO sqlite_stat1 VALUES('PARTSUPP','pspki','80000 4 1');
INSERT INTO sqlite_stat1 VALUES('SUPPLIER','snki','1000 40');
INSERT INTO sqlite_stat1 VALUES('SUPPLIER','spki','1000 1');
INSERT INTO sqlite_stat1 VALUES('PART','bootleg_pti','20000 134');
INSERT INTO sqlite_stat1 VALUES('PART','bootleg_psi','20000 400');
INSERT INTO sqlite_stat1 VALUES('PART','ppki','20000 1');
INSERT INTO sqlite_stat1 VALUES('REGION','rpki','5 1');
INSERT INTO sqlite_stat1 VALUES('NATION','bootleg_nni','25 1');
INSERT INTO sqlite_stat1 VALUES('NATION','nrki','25 5');
INSERT INTO sqlite_stat1 VALUES('NATION','npki','25 1');
ANALYZE sqlite_master;
} {}
do_test tpch01-1.1 {
unset -nocomplain ::eqpres
set ::eqpres [db eval {EXPLAIN QUERY PLAN
select
o_year,
sum(case
when nation = 'EGYPT' then volume
else 0
end) / sum(volume) as mkt_share
from
(
select
strftime('%Y', o_orderdate) as o_year,
l_extendedprice * (1 - l_discount) as volume,
n2.n_name as nation
from
part,
supplier,
lineitem,
orders,
customer,
nation n1,
nation n2,
region
where
p_partkey = l_partkey
and s_suppkey = l_suppkey
and l_orderkey = o_orderkey
and o_custkey = c_custkey
and c_nationkey = n1.n_nationkey
and n1.n_regionkey = r_regionkey
and r_name = 'MIDDLE EAST'
and s_nationkey = n2.n_nationkey
and o_orderdate between '1995-01-01' and '1996-12-31'
and p_type = 'LARGE PLATED STEEL'
) as all_nations
group by
o_year
order by
o_year;}]
set ::eqpres
} {/0 0 0 {SEARCH TABLE part USING INDEX bootleg_pti .P_TYPE=..} 0 1 2 {SEARCH TABLE lineitem USING INDEX lpki2 .L_PARTKEY=..}.*/}
do_test tpch01-1.1b {
set ::eqpres
} {/.* customer .* nation AS n1 .* nation AS n2 .*/}
do_eqp_test tpch01-1.2 {
select
c_custkey, c_name, sum(l_extendedprice * (1 - l_discount)) as revenue,
c_acctbal, n_name, c_address, c_phone, c_comment
from
customer, orders, lineitem, nation
where
c_custkey = o_custkey and l_orderkey = o_orderkey
and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month')
and l_returnflag = 'R' and c_nationkey = n_nationkey
group by
c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment
order by
revenue desc;
} {0 0 1 {SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)} 0 1 0 {SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)} 0 2 3 {SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)} 0 3 2 {SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
+29
View File
@@ -1304,4 +1304,33 @@ do_test where-17.5 {
}
} {42 1 43 1}
# Ticket [be84e357c035d068135f20bcfe82761bbf95006b] 2013-09-03
# Segfault during query involving LEFT JOIN column in the ORDER BY clause.
#
do_execsql_test where-18.1 {
CREATE TABLE t181(a);
CREATE TABLE t182(b,c);
INSERT INTO t181 VALUES(1);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL;
} {1}
do_execsql_test where-18.2 {
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
} {1}
do_execsql_test where-18.3 {
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c;
} {1}
do_execsql_test where-18.4 {
INSERT INTO t181 VALUES(1),(1),(1),(1);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +c;
} {1}
do_execsql_test where-18.5 {
INSERT INTO t181 VALUES(2);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY c IS NULL, +a;
} {1 2}
do_execsql_test where-18.6 {
INSERT INTO t181 VALUES(2);
SELECT DISTINCT a FROM t181 LEFT JOIN t182 ON a=b ORDER BY +a, +c IS NULL;
} {1 2}
finish_test
+8 -3
View File
@@ -781,11 +781,11 @@ do_test where9-6.8.2 {
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
} {1 {no query solution}}
ifcapable stat3 {
ifcapable stat4||stat3 {
# When STAT3 is enabled, the "b NOT NULL" terms get translated
# into b>NULL, which can be satified by the index t1b. It is a very
# expensive way to do the query, but it works, and so a solution is possible.
do_test where9-6.8.3-stat3 {
do_test where9-6.8.3-stat4 {
catchsql {
UPDATE t1 INDEXED BY t1b SET a=a+100
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
@@ -793,7 +793,7 @@ ifcapable stat3 {
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
}
} {0 {}}
do_test where9-6.8.4-stat3 {
do_test where9-6.8.4-stat4 {
catchsql {
DELETE FROM t1 INDEXED BY t1b
WHERE (b IS NULL AND c NOT NULL AND d NOT NULL)
@@ -851,6 +851,11 @@ do_test where9-7.0 {
INSERT INTO t6 SELECT * FROM t5;
ANALYZE t5;
}
ifcapable stat3 {
sqlite3 db2 test.db
db2 eval { DROP TABLE IF EXISTS sqlite_stat3 }
db2 close
}
} {}
do_test where9-7.1.1 {
count_steps {
+7
View File
@@ -112,4 +112,11 @@ foreach {tn sql} {
} {/.*SCAN TABLE t2\y.*SEARCH TABLE t1\y.*/}
}
do_execsql_test 4.0 {
CREATE TABLE t4(a,b,c,d,e, PRIMARY KEY(a,b,c));
CREATE INDEX t4adc ON t4(a,d,c);
CREATE UNIQUE INDEX t4aebc ON t4(a,e,b,c);
EXPLAIN QUERY PLAN SELECT rowid FROM t4 WHERE a=? AND b=?;
} {/a=. AND b=./}
finish_test
+102
View File
@@ -0,0 +1,102 @@
# 2013 August 27
#
# 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 the file name handling provided
# by the "win32-longpath" VFS.
#
if {$tcl_platform(platform)!="windows"} return
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix win32longpath
db close
set path [file nativename [get_pwd]]
sqlite3 db [file join $path test.db] -vfs win32-longpath
do_test 1.1 {
db eval {
BEGIN EXCLUSIVE;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
INSERT INTO t1 VALUES(4);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {1 2 3 4}
set longPath(1) \\\\?\\$path\\[pid]
make_win32_dir $longPath(1)
set longPath(2) $longPath(1)\\[string repeat X 255]
make_win32_dir $longPath(2)
set longPath(3) $longPath(2)\\[string repeat Y 255]
make_win32_dir $longPath(3)
set fileName $longPath(3)\\test.db
do_test 1.2 {
list [catch {sqlite3 db2 [string range $fileName 4 end]} msg] $msg
} {1 {unable to open database file}}
sqlite3 db3 $fileName -vfs win32-longpath
do_test 1.3 {
db3 eval {
BEGIN EXCLUSIVE;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(5);
INSERT INTO t1 VALUES(6);
INSERT INTO t1 VALUES(7);
INSERT INTO t1 VALUES(8);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {5 6 7 8}
db3 close
# puts " Database exists \{[exists_win32_path $fileName]\}"
sqlite3 db3 $fileName -vfs win32-longpath
do_test 1.4 {
db3 eval {
PRAGMA journal_mode = WAL;
}
} {wal}
do_test 1.5 {
db3 eval {
BEGIN EXCLUSIVE;
INSERT INTO t1 VALUES(9);
INSERT INTO t1 VALUES(10);
INSERT INTO t1 VALUES(11);
INSERT INTO t1 VALUES(12);
SELECT x FROM t1 ORDER BY x;
COMMIT;
}
} {5 6 7 8 9 10 11 12}
db3 close
# puts " Database exists \{[exists_win32_path $fileName]\}"
do_delete_win32_file $fileName
# puts " Files remaining \{[find_win32_file $longPath(3)\\*]\}"
do_remove_win32_dir $longPath(3)
do_remove_win32_dir $longPath(2)
do_remove_win32_dir $longPath(1)
finish_test
+8 -2
View File
@@ -137,7 +137,7 @@ proc section_comment {text} {
# Read the source file named $filename and write it into the
# sqlite3.c output file. If any #include statements are seen,
# process them approprately.
# process them appropriately.
#
proc copy_file {filename} {
global seen_hdr available_hdr out addstatic linemacros
@@ -169,8 +169,14 @@ proc copy_file {filename} {
} elseif {![info exists seen_hdr($hdr)]} {
set seen_hdr($hdr) 1
puts $out $line
} elseif {[regexp {/\*\s+amalgamator:\s+keep\s+\*/} $line]} {
# This include file must be kept because there was a "keep"
# directive inside of a line comment.
puts $out $line
} else {
puts $out "/* $line */"
# Comment out the entire line, replacing any nested comment
# begin/end markers with the harmless substring "**".
puts $out "/* [string map [list /* ** */ **] $line] */"
}
} elseif {[regexp {^#ifdef __cplusplus} $line]} {
puts $out "#if 0"