Compare commits

..

152 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
drh f68060839c Version 3.8.0
FossilOrigin-Name: f64cd21e2e23ed7cff48f7dafa5e76adde9321c2
2013-08-26 04:50:08 +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 feb56e0e17 Adjust #ifdefs to get SQLITE_OMIT_AUTOMATIC_INDEX and SQLITE_OMIT_PAGER_PRAGMAS
to build.

FossilOrigin-Name: ed310201628cf79c0f57674ae7478ee6738b1c6e
2013-08-23 17:33:46 +00:00
drh 1efd81f7cf Fix a requirements comment in a test case. No changes to the testcase
itself nor to any code.

FossilOrigin-Name: 3ad1f998e5db044849b528c31c4a7e1f3d527320
2013-08-23 16:47:40 +00:00
dan 7dd8d0a87b Modify script mkautoconfamal.sh to use the download.html naming convention for the tar.gz it creates.
FossilOrigin-Name: 375b4e3db0e0c9e83034d1c33d7c57aca48e87b6
2013-08-23 12:04:52 +00:00
drh cc04afdad0 Defer the creation of automatic indices until the index is actually used.
FossilOrigin-Name: 0775501acf152dcbf4dd039f4511f3d8c4330d85
2013-08-22 02:56:28 +00:00
drh b00fc3b14e Simplify the btreeGetPage() routine so that it uses a single flag parameter
in place of two boolean parameters.

FossilOrigin-Name: 617e23ec283d3147fc3fd29c474ccedf4915cdc7
2013-08-21 23:42:32 +00:00
drh 9d1ab0794e Minor performance tweaks to the pager.
FossilOrigin-Name: 9ae1f9ce7ea6beaeddc3711080b3796e05acc4f8
2013-08-21 22:54:55 +00:00
drh cf5ff12105 Refactor the sqlite3_randomness() implementation for improved performance.
FossilOrigin-Name: 4144dffb57b5ed791d7a6d2f26fab5e7dc77fbd1
2013-08-21 22:09:25 +00:00
drh b49bc86a1a Simplification to the StrAccum object and the sqlite3StrAccumAppend()
method that also results in slightly better performance.

FossilOrigin-Name: 700dbbea8647e0fdaee6d0aba3d3dd8ebfbac04a
2013-08-21 21:12:10 +00:00
dan c63e880bdb Minor fixes for test cases. No code changes.
FossilOrigin-Name: ef2a6a37366f91889dc2f1ba9cb6d1257d9b05db
2013-08-21 20:04:54 +00:00
mistachkin 47b2995983 Fix typo in test.
FossilOrigin-Name: f9859fe93bcecb4be7c1034291018523124c4a5c
2013-08-21 19:59:14 +00:00
drh e7ecdfabd2 Update sqlite3MemCompare() to try common cases first, for a modest speed
improvement.

FossilOrigin-Name: b25bac79191975149d88fe34618c74354de62c5e
2013-08-21 19:13:53 +00:00
dan 016f7811f2 If a virtual table xSync() returns an error message, copy it into a buffer allocated by sqlite3DbMalloc() before transfering it to Vdbe.zErrMsg.
FossilOrigin-Name: 854ba3049005adf033e07e6740a36e63f2a56758
2013-08-21 17:35:48 +00:00
drh 13c77bf86b Performance enhancement in btreeParseCellPtr().
FossilOrigin-Name: a17190a2296e8cd5e59524ff5914fc5ea3560697
2013-08-21 15:52:22 +00:00
dan 2505a5fee2 Fix an FTS4 problem introduced by [361084e1eb].
FossilOrigin-Name: 5f35c8cb8f8b67121c70f98c02c4aa7c25327690
2013-08-21 15:45:27 +00:00
dan 36e78309de Candidate fix for [d666d600a6].
FossilOrigin-Name: 781592f32c8e1dcd59954c17211cf61349d1c0b1
2013-08-21 12:04:32 +00:00
dan 22c745a9c9 Fix a minor problem in progress.test. No code changes.
FossilOrigin-Name: a95ae93b32a9ad2ae017124ed0881802c3c741c0
2013-08-21 07:25:03 +00:00
dan c3c16cbd61 Fix a couple of test scripts to work with DEFAULT_AUTOVACUUM and OMIT_VIRTUALTABLE.
FossilOrigin-Name: 356c6c59311eaf7d5633476f635e94a12b8b3924
2013-08-20 20:25:03 +00:00
dan e934e633a5 Fix an invalid assert() in where.c. Also a crash that can occur in the EXPLAIN QUERY PLAN code under obscure circumstances.
FossilOrigin-Name: ef192abb82c2fc31135f875d7a19908d67c076b0
2013-08-20 17:14:57 +00:00
drh d0aa2f3afd Ignore IS NOT NULL and NOT NULL constraints on NOT NULL columns.
FossilOrigin-Name: e476408e3c5ba5f3ba5e98ff264167c163d72e3f
2013-08-20 17:00:55 +00:00
dan 4044906210 Test script changes to support testing sqlite3_interrupt().
FossilOrigin-Name: 0cede9f898bcd13dab51b25cb0e72213d988d3d2
2013-08-20 16:08:39 +00:00
drh 9b47ee3f09 Performance optimizations in the VDBE and especially to the OP_Next and
related opcodes and in the sqlite3BtreeNext() and sqlite3BtreePrevious()
routines.  This is a cherrypick of [6f99b54aedeb], [d2efea1682a7], and
[d78c5d89de4b].

FossilOrigin-Name: 7f72fc4f47445a2c01910b268335873de9f75059
2013-08-20 03:13:51 +00:00
drh f66f26a311 Performance improvement in sqlite3BtreeNext() and sqlite3BtreePrevious()
for the common case of a valid cursor.

FossilOrigin-Name: dc65ad8c4c67b21e3b042b8df6580d02b634a90b
2013-08-19 20:04:10 +00:00
dan 2c18788ffa Initialize a variable in fts3_write.c on the grounds that the argument required to show that it does not require initialization with is complicated. Add an assert() to where.c to silence a clang scan-build warning.
FossilOrigin-Name: d6c4d48a002a6d7057fccc30064ce0b049678f0c
2013-08-19 19:29:50 +00:00
dan e704713cb8 Fix test script pragma2.test so that it works with ENABLE_MEMORY_MANAGEMENT.
FossilOrigin-Name: 6acf728100ff339e4451bcefd3a20fd5c3cfd662
2013-08-19 18:37:18 +00:00
dan 290703091e Add some extra assert() statements to silence a few clang warnings.
FossilOrigin-Name: 1c63e9515b5f5cb9169928b108d002dcd18ad4fd
2013-08-19 18:17:03 +00:00
drh 4ccc419b3c Remove unused variables from the command-line shell sources.
FossilOrigin-Name: 753a402e90f3c9f675155ea96ee048dbe7a68700
2013-08-19 14:23:31 +00:00
drh 9e48788e9d Fix a potential reference off the end of an array in the query planner.
FossilOrigin-Name: f15591f80212dd6d4ed8e0f14be691cd578d4cdf
2013-08-19 14:19:00 +00:00
drh 77dfd5bb44 Fixes for harmless compiler warnings.
FossilOrigin-Name: a0d9ca4f07f1dc3a189864f8ed9cdb0b1d791b1a
2013-08-19 11:15:48 +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
drh 45e3215db0 Add the cache_spill pragma. Change the fullfsync and checkpoint_fullfsync
pragmas to apply to all attached databases.

FossilOrigin-Name: 65a85a156f3c827890e9f1fd22484a2f875c3b6f
2013-08-17 16:37:04 +00:00
drh d3605a4f20 The fullfsync, checkpoint_fullfsync, and cache_spill pragmas apply to all
files of a database connection, including those opened by future ATTACH
statements.

FossilOrigin-Name: d07c4331a28d44deca1ece8a34118f5b121b3ee2
2013-08-17 15:42:29 +00:00
drh d4b5c60eca Test cases for the cache_spill pragma.
FossilOrigin-Name: b85c9ec5e02c1b92faa8eeb9e56e02a576a43a96
2013-08-17 00:25:07 +00:00
drh 40c3941cfa Add the cache_spill pragma.
FossilOrigin-Name: cdb181c04fa99c6c29f23eb68ccb5475e7f6bf9c
2013-08-16 20:42:20 +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
drh 0af16ab2c2 Make sure that GROUP BY terms select input column names in preference to
output column names, in compliance with the SQL standard.
Ticket [1c69be2dafc28].

FossilOrigin-Name: f2d175f975cd0be63425424ec322a98fb650019e
2013-08-15 22:40:21 +00:00
drh e35463b312 Bare identifiers in ORDER BY clauses bind more tightly to output column name,
but identifiers in expressions bind more tightly to input column names.
This is a compromise between SQL92 and SQL99 behavior and is what
PostgreSQL and MS-SQL do.  Ticket [f617ea3125e9c].

FossilOrigin-Name: c78b357c00a35ed48ce2ffbc041de8d22570d1e2
2013-08-15 20:24:27 +00:00
mistachkin fc7df53aee Make it easy to attach a debugger the test fixture process prior to any tests being run.
FossilOrigin-Name: 53cd9ebfaf401c7932bf591e134a527c9962b88e
2013-08-15 20:05:03 +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
drh 26080d9241 Clarification and typo fixes in comments related to name resolution.
No changes to code.

FossilOrigin-Name: f30abdf9d814d6c75bf1c803054737c737ad636f
2013-08-15 14:27:42 +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
100 changed files with 6364 additions and 1886 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
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.
# 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'
PACKAGE_STRING='sqlite 3.8.0'
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 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:";;
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
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, 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, 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
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)
##########
+1
View File
@@ -504,6 +504,7 @@ static int fts3StringAppend(
pStr->z = zNew;
pStr->nAlloc = nAlloc;
}
assert( pStr->z!=0 && (pStr->nAlloc >= pStr->n+nAppend+1) );
/* Append the data to the string buffer. */
memcpy(&pStr->z[pStr->n], zAppend, nAppend);
+7 -7
View File
@@ -1461,7 +1461,7 @@ static int fts3SegReaderNextDocid(
/* The following line of code (and the "p++" below the while() loop) is
** normally all that is required to move pointer p to the desired
** position. The exception is if this node is being loaded from disk
** incrementally and pointer "p" now points to the first byte passed
** incrementally and pointer "p" now points to the first byte past
** the populated part of pReader->aNode[].
*/
while( *p | c ) c = *p++ & 0x80;
@@ -2848,8 +2848,8 @@ int sqlite3Fts3SegReaderStep(
fts3SegReaderSort(apSegment, nMerge, nMerge, xCmp);
while( apSegment[0]->pOffsetList ){
int j; /* Number of segments that share a docid */
char *pList;
int nList;
char *pList = 0;
int nList = 0;
int nByte;
sqlite3_int64 iDocid = apSegment[0]->iDocid;
fts3SegReaderNextDocid(p, apSegment[0], &pList, &nList);
@@ -5135,11 +5135,11 @@ int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *pCsr){
if( pTC ) pModule->xClose(pTC);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
}
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
if( pDef->pList ){
rc = fts3PendingListAppendVarint(&pDef->pList, 0);
}
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
if( pDef->pList ){
rc = fts3PendingListAppendVarint(&pDef->pList, 0);
}
}
}
+106 -99
View File
@@ -1,12 +1,12 @@
C Make\sit\seasy\sto\sattach\sa\sdebugger\sthe\stest\sfixture\sprocess\sprior\sto\sany\stests\sbeing\srun.
D 2013-08-15T08:06:15.562
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 f135b651727f978b7191bd6fa12c7fc1e13e13ac
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 27e9279a219b652bd1c53439353a5e5be70214b2 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
@@ -87,7 +87,7 @@ F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
F ext/fts3/fts3_porter.c a465b49fcb8249a755792f87516eff182efa42b3
F ext/fts3/fts3_snippet.c 5fcfcafff46a2a3a63b8e59fcb51987d01c74695
F ext/fts3/fts3_snippet.c e8ee8c101dd9cfbc9568d134e869d2bd2f7f6d4d
F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763
F ext/fts3/fts3_test.c f9a1a1702db1bfad3e2d0064746eeb808f125489
F ext/fts3/fts3_tokenize_vtab.c 011170fe9eba5ff062f1a31d3188e00267716706
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
F ext/fts3/fts3_write.c cd264daa4f92b8eb6d61245333d0e3b147e8fd80
F ext/fts3/fts3_write.c ce45c3ea578464f26b0293ea8e54a39694f18b64
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
@@ -155,41 +155,41 @@ F mptest/multiwrite01.test 499ad0310da8dff8e8f98d2e272fc2a8aa741b2e
F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
F src/analyze.c a33fcb0b3a399d966951feb9f32115106b3ecc2e
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
F src/analyze.c d322972af09e3f8debb45f420dfe3ded142b108b
F src/attach.c 4a2b6a6d9b5f9fd55a8b59488ff7929fef73a195
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a
F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c cee4724668ebc09bb482c1be30f96e0ae2474f9b
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
F src/btree.c b9b57df546df2636294bfb21a986f5707b417df2
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
F src/btreeInt.h 51cf220a9b9223354770883e93a859dc377aa27f
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 0bbb44462a19169189b2709fbbd800950521b5ae
F src/delete.c 2dc64ca360b7d7da481183ea920a813a0c203c97
F src/expr.c 7f93e51fd7ca0d3ea1be2715a29c86a69e7b1e93
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
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 4e4cd5c2ee09db496c0dde79b507bba6b8bcbdcb
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/pager.c 5d2f7475260a8588f9c441bb309d2b7eaa7ded3b
F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
F src/parse.y 27c6b4138497d6f8360ba7847da6ed48033f957f
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 a97566d6da75075589a7c716d1bda14b586cf8da
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938
F src/pragma.c 590c75750d93ec5a1f903e4bb0dc6d2a0845bf8b
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
F src/pragma.c 3aa3d8c8623b7b71c5b1bfb72dcc31fb0c25665f
F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
F src/resolve.c d336be12493bb376c6756c214379c727cd8c01a8
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 8b148eb851f384412aea57091659d14b369918ca
F src/shell.c 927e17b37b63b24461e372d982138fb22c4df321
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 def0e436c0d4ca5084305ca6ae898020fbafaae4
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 4914ae1d00045a5310aea9e0f7c9a8edd3d9f856
F src/vdbe.c a393a94c0d77b86c7c4ad2cfb43ec4ba278d9596
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231
F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b
F src/vdbeaux.c a6ea36a9dc714e1128a0173249a0532ddcab0489
F src/vdbeInt.h cbe71b8b36d8b3bba5709cc3f436c7e3b47b7b08
F src/vdbeapi.c 96b24b946cf21894f63d9393e821baa2f0a80979
F src/vdbeaux.c 88beca92f2ed0bbe2c6f87946d0e999a6807ea1b
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
F src/vdbemem.c 817ce21ab4ca57f902619bb8fef3f8a51bbd0ed8
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624
F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
F src/where.c ea01a52eb31e54dda97b8e39c2e5b38faa13dce5
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
@@ -367,7 +370,7 @@ F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
F test/collate1.test b709989e6e6ff6e1d2bd64231c2c1d8146846c9e
F test/collate2.test 285cef1b58ce2b3cf074a386f763ce753c81c97f
F test/collate2.test 9aaa410a00734e48bcb27f3872617d6f69b2a621
F test/collate3.test 79558a286362cb9ed603c6fa543f1cda7f563f0f
F test/collate4.test 031f7265c13308b724ba3c49f41cc04612bd92b1
F test/collate5.test 65d928034d30d2d263a80f6359f7549ee1598ec6
@@ -395,7 +398,7 @@ F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb
F test/corruptD.test 3b09903a2e2fe07ecafe775fea94177f8a4bb34f
F test/corruptE.test d3a3d7e864a95978195741744dda4abfd8286018
F test/corruptF.test 1c7b6f77cf3f237fb7fbb5b61d6c921fd4c7b993
F test/corruptG.test d18ee5169e10a76bccb7b115e551bc31087a525e
F test/corruptG.test c67fd860e9e3943bc90b856a3049c9a28827167e
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
@@ -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
@@ -430,7 +433,7 @@ F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
F test/e_expr.test d5cdda0e4ffb17760858ed4c7c4ece07efc40f71
F test/e_fkey.test 17cfb40002d165299681f39aac0cb5890c359935
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test ea84688f3b27a6a3728e4ae7a7d9ad342579d7a4
F test/e_insert.test 291e056e1a442a5e5166a989a8a03a46e38225ca
F test/e_reindex.test e175794fc41f8e8aef34772e87a7d7b7a9251dd3
F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
F test/e_select.test f2358d074bd82240bc79a8348f284a2a8909dc1f
@@ -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
@@ -535,7 +539,7 @@ F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
F test/fts3fault2.test 3198eef2804deea7cac8403e771d9cbcb752d887
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
F test/fts3matchinfo.test 3f297e14e3f0d5be8595246f5fcd426625cc5881
F test/fts3matchinfo.test ff423e73faab8fc6d7adeefedf74dd8e2b0b14e0
F test/fts3near.test 12895557870b0f9af7cc0be81a0171abb2d12f12
F test/fts3prefix.test b36d4f00b128a51e7b386cc013a874246d9d7dc1
F test/fts3prefix2.test e1f0a822ca661dced7f12ce392e14eaf65609dce
@@ -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,8 +594,8 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
F test/index6.test f53a788b813eb6937346867bae9e587c434dd9a1
F test/indexedby.test 0e959308707c808515c3a51363f7a9835027108c
F test/index6.test e96324d8c1ade4b30a4c6cee14b1fc2e5a367cda
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 489aa12a027c83d291f5034a83c8c32e6be1dca2
@@ -644,12 +648,12 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test a577cbbcc1594c7763b9b3515b3633555751c7f0
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
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
@@ -661,7 +665,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
F test/malloc_common.tcl 58e54229c4132ef882a11fab6419ec4cd3073589
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test db5260330676de007be8530d6ecc7c9ab2b06ad3
@@ -714,11 +718,11 @@ 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 3a55f82b954242c642f8342b17dffc8b47472947
F test/pragma2.test 224f0381f9411a78ae685cac24c13656a62021b7
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/progress.test 552dc1edc37333a8d3098b8c26a2b7f06f5799d7
F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
@@ -733,7 +737,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
F test/resolver01.test d1b487fc567bdb70b5dd09ccaaa877ddc61a233e
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
F test/rollback.test a1b4784b864331eae8b2a98c189efa2a8b11ff07
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
@@ -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
@@ -857,6 +861,7 @@ F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5
F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
F test/tkt-b1d3a2e531.test 610ef582413171b379652663111b1f996d9f8f78
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
@@ -864,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
@@ -906,7 +911,7 @@ F test/tkt2686.test 6ee01c9b9e9c48f6d3a1fdd553b1cc4258f903d6
F test/tkt2767.test 569000d842678f9cf2db7e0d1b27cbc9011381b0
F test/tkt2817.test f31839e01f4243cff7399ef654d3af3558cb8d8d
F test/tkt2820.test 39940276b3436d125deb7d8ebeee053e4cf13213
F test/tkt2822.test c3589494fba643e039bcf0bfde7554ff6028406d
F test/tkt2822.test f391776423a7c0d0949edfce375708bfb0f3141e
F test/tkt2832.test a9b0b74a02dca166a04d9e37739c414b10929caa
F test/tkt2854.test e432965db29e27e16f539b2ba7f502eb2ccc49af
F test/tkt2920.test a8737380e4ae6424e00c0273dc12775704efbebf
@@ -959,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
@@ -1038,25 +1044,26 @@ 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/where2.test b1830f762f837153a4c9743adaab90a5761f73e7
F test/where3.test a0682ba3dc8c8f46ffcc95a3d9f58c4327fc129f
F test/where.test 8d66dfbfd4d12816f74f854dbf67dee492c06267
F test/where2.test 76d5346f7edb2a6a0442dcf3e9d088ac6903e0b5
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
F test/where8.test 6f95896633cf2d307b5263145b942b7d33e837c6
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
F test/where9.test 9a7fda4a4512abc26a855e8b2b6572b200f6019b
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
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
@@ -1070,12 +1077,12 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/lemon.c 680980c7935bfa1edec20c804c9e5ba4b1dd96f5
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
F tool/mkautoconfamal.sh 9ef9ad69bc3021a6fd2dac53a2e8cf5b97e0df05
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
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
@@ -1105,10 +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 9e999081a59b161a0a1f968fbc01a1db9ea43b93
R c32412a10fe0450296a67115895879b1
T *branch * dbgTestFixture
T *sym-dbgTestFixture *
P 75a8a8c1b39725d36db627536d0c69401f8e0815
R 14e40117cf5ed4a868935b4adf8b8b0d
T *branch * expr-tuning
T *sym-expr-tuning *
T -sym-trunk *
U mistachkin
Z 7b47b87c7211179488e7ecca78b01825
U drh
Z e578fc31598c846285e1a40bbc280fc4
+1 -1
View File
@@ -1 +1 @@
c23acba11bfefc019b5945cfb345f9afcf4b6242
579a512538528cf4bb4381ba393c5d9e7310086b
+1 -1
View File
@@ -7,7 +7,7 @@ includedir=@includedir@
Name: SQLite
Description: SQL database engine
Version: @RELEASE@
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lsqlite3
Libs.private: @LIBS@
Cflags: -I${includedir}
+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
+6 -5
View File
@@ -158,6 +158,9 @@ static void attachFunc(
sqlite3PagerLockingMode(pPager, db->dfltLockMode);
sqlite3BtreeSecureDelete(aNew->pBt,
sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) );
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
sqlite3BtreeSetPagerFlags(aNew->pBt, 3 | (db->flags & PAGER_FLAGS_MASK));
#endif
}
aNew->safety_level = 3;
aNew->zName = sqlite3DbStrDup(db, zName);
@@ -376,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 */
@@ -398,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 */
@@ -508,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 -1
View File
@@ -392,7 +392,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
DbPage *pSrcPg; /* Source page object */
rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
PAGER_ACQUIRE_READONLY);
PAGER_GET_READONLY);
if( rc==SQLITE_OK ){
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg);
+92 -67
View File
@@ -724,6 +724,9 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
if( pCur->skipNext && pCur->eState==CURSOR_VALID ){
pCur->eState = CURSOR_SKIPNEXT;
}
}
return rc;
}
@@ -749,7 +752,7 @@ int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
*pHasMoved = 1;
return rc;
}
if( pCur->eState!=CURSOR_VALID || pCur->skipNext!=0 ){
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
*pHasMoved = 1;
}else{
*pHasMoved = 0;
@@ -937,7 +940,8 @@ static void btreeParseCellPtr(
assert( n==4-4*pPage->leaf );
if( pPage->intKey ){
if( pPage->hasData ){
n += getVarint32(&pCell[n], nPayload);
assert( n==0 );
n = getVarint32(pCell, nPayload);
}else{
nPayload = 0;
}
@@ -1581,15 +1585,12 @@ static int btreeGetPage(
BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */
int noContent, /* Do not load page content if true */
int bReadonly /* True if a read-only (mmap) page is ok */
int flags /* PAGER_GET_NOCONTENT or PAGER_GET_READONLY */
){
int rc;
DbPage *pDbPage;
int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
| (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
assert( noContent==0 || bReadonly==0 );
assert( flags==0 || flags==PAGER_GET_NOCONTENT || flags==PAGER_GET_READONLY );
assert( sqlite3_mutex_held(pBt->mutex) );
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc;
@@ -1637,15 +1638,16 @@ static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
int bReadonly /* True if a read-only (mmap) page is ok */
int bReadonly /* PAGER_GET_READONLY or 0 */
){
int rc;
assert( sqlite3_mutex_held(pBt->mutex) );
assert( bReadonly==PAGER_GET_READONLY || bReadonly==0 );
if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
rc = btreeGetPage(pBt, pgno, ppPage, bReadonly);
if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){
@@ -2165,17 +2167,14 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
** probability of damage to near zero but with a write performance reduction.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
int sqlite3BtreeSetSafetyLevel(
int sqlite3BtreeSetPagerFlags(
Btree *p, /* The btree to set the safety level on */
int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
int fullSync, /* PRAGMA fullfsync. */
int ckptFullSync /* PRAGMA checkpoint_fullfync */
unsigned pgFlags /* Various PAGER_* flags */
){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
assert( level>=1 && level<=3 );
sqlite3BtreeEnter(p);
sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync, ckptFullSync);
sqlite3PagerSetFlags(pBt->pPager, pgFlags);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
@@ -2381,7 +2380,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->pPage1==0 );
rc = sqlite3PagerSharedLock(pBt->pPager);
if( rc!=SQLITE_OK ) return rc;
rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
rc = btreeGetPage(pBt, 1, &pPage1, 0);
if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is
@@ -2509,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:
@@ -2963,7 +2963,7 @@ static int relocatePage(
** iPtrPage.
*/
if( eType!=PTRMAP_ROOTPAGE ){
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3047,7 +3047,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3446,7 +3446,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
/* The rollback may have destroyed the pPage1->aData value. So
** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@@ -3881,7 +3881,7 @@ static int getOverflowPage(
assert( next==0 || rc==SQLITE_DONE );
if( rc==SQLITE_OK ){
rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
rc = btreeGetPage(pBt, ovfl, &pPage, (ppPage==0) ? PAGER_GET_READONLY : 0);
assert( rc==SQLITE_OK || pPage==0 );
if( rc==SQLITE_OK ){
next = get4byte(pPage->aData);
@@ -4103,7 +4103,7 @@ static int accessPayload(
{
DbPage *pDbPage;
rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
(eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
(eOp==0 ? PAGER_GET_READONLY : 0)
);
if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage);
@@ -4287,7 +4287,8 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
rc = getAndInitPage(pBt, newPgno, &pNewPage,
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
if( rc ) return rc;
pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0;
@@ -4404,7 +4405,8 @@ static int moveToRoot(BtCursor *pCur){
pCur->eState = CURSOR_INVALID;
return SQLITE_OK;
}else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0],
pCur->wrFlag==0 ? PAGER_GET_READONLY : 0);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -4799,21 +4801,29 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pRes!=0 );
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
return rc;
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext>0 ){
pCur->skipNext = 0;
*pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
}
}
if( pCur->skipNext>0 ){
pCur->skipNext = 0;
*pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
pPage = pCur->apPage[pCur->iPage];
idx = ++pCur->aiIdx[pCur->iPage];
@@ -4831,7 +4841,10 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
if( idx>=pPage->nCell ){
if( !pPage->leaf ){
rc = moveToChild(pCur, get4byte(&pPage->aData[pPage->hdrOffset+8]));
if( rc ) return rc;
if( rc ){
*pRes = 0;
return rc;
}
rc = moveToLeftmost(pCur);
*pRes = 0;
return rc;
@@ -4873,21 +4886,32 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
MemPage *pPage;
assert( cursorHoldsMutex(pCur) );
rc = restoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
assert( pRes!=0 );
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
pCur->atLast = 0;
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
if( pCur->eState!=CURSOR_VALID ){
if( ALWAYS(pCur->eState>=CURSOR_REQUIRESEEK) ){
rc = btreeRestoreCursorPosition(pCur);
if( rc!=SQLITE_OK ){
*pRes = 0;
return rc;
}
}
if( CURSOR_INVALID==pCur->eState ){
*pRes = 1;
return SQLITE_OK;
}
if( pCur->skipNext ){
assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_SKIPNEXT );
pCur->eState = CURSOR_VALID;
if( pCur->skipNext<0 ){
pCur->skipNext = 0;
*pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
}
}
if( pCur->skipNext<0 ){
pCur->skipNext = 0;
*pRes = 0;
return SQLITE_OK;
}
pCur->skipNext = 0;
pPage = pCur->apPage[pCur->iPage];
assert( pPage->isInit );
@@ -4895,6 +4919,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
int idx = pCur->aiIdx[pCur->iPage];
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
if( rc ){
*pRes = 0;
return rc;
}
rc = moveToRightmost(pCur);
@@ -5018,7 +5043,7 @@ static int allocateBtreePage(
if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT;
}else{
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
}
if( rc ){
pTrunk = 0;
@@ -5082,7 +5107,7 @@ static int allocateBtreePage(
goto end_allocate_page;
}
testcase( iNewTrunk==mxPage );
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
goto end_allocate_page;
}
@@ -5161,8 +5186,8 @@ static int allocateBtreePage(
memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
}
put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
noContent = !btreeGetHasContent(pBt, *pPgno) ? PAGER_GET_NOCONTENT : 0;
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -5194,7 +5219,7 @@ static int allocateBtreePage(
** here are confined to those pages that lie between the end of the
** database image and the end of the database file.
*/
int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate)) ? PAGER_GET_NOCONTENT : 0;
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc ) return rc;
@@ -5210,7 +5235,7 @@ static int allocateBtreePage(
MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg);
@@ -5224,7 +5249,7 @@ static int allocateBtreePage(
*pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent);
if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
@@ -5292,7 +5317,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros.
*/
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) )
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
){
goto freepage_out;
@@ -5319,7 +5344,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0);
if( rc!=SQLITE_OK ){
goto freepage_out;
}
@@ -5365,7 +5390,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list.
*/
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){
goto freepage_out;
}
rc = sqlite3PagerWrite(pPage->pDbPage);
@@ -7264,7 +7289,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
}
/* Move the page currently at pgnoRoot to pgnoMove. */
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -7285,7 +7310,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
if( rc!=SQLITE_OK ){
return rc;
}
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -7463,7 +7488,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE;
}
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0);
if( rc ){
@@ -7498,7 +7523,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*/
MemPage *pMove;
releasePage(pPage);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -7508,7 +7533,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return rc;
}
pMove = 0;
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0);
freePage(pMove, &rc);
releasePage(pMove);
if( rc!=SQLITE_OK ){
@@ -7723,7 +7748,7 @@ static void checkAppendMsg(
}
sqlite3VXPrintf(&pCheck->errMsg, 1, zFormat, ap);
va_end(ap);
if( pCheck->errMsg.mallocFailed ){
if( pCheck->errMsg.accError==STRACCUM_NOMEM ){
pCheck->mallocFailed = 1;
}
}
@@ -7920,7 +7945,7 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
+1 -1
View File
@@ -64,7 +64,7 @@ int sqlite3BtreeOpen(
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
int sqlite3BtreeGetPageSize(Btree*);
+11 -5
View File
@@ -520,14 +520,19 @@ struct BtCursor {
/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_INVALID:
** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_SKIPNEXT:
** Cursor is valid except that the Cursor.skipNext field is non-zero
** indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious()
** operation should be a no-op.
**
** CURSOR_REQUIRESEEK:
** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
@@ -544,8 +549,9 @@ struct BtCursor {
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2
#define CURSOR_FAULT 3
#define CURSOR_SKIPNEXT 2
#define CURSOR_REQUIRESEEK 3
#define CURSOR_FAULT 4
/*
** The database page the PENDING_BYTE occupies. This page is never used.
+2 -2
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) ){
@@ -2866,7 +2866,7 @@ Index *sqlite3CreateIndex(
** the zStmt variable
*/
if( pStart ){
int n = (pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
int n = (int)(pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
if( pName->z[n-1]==';' ) n--;
/* A named index with an explicit CREATE INDEX statement */
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
+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,
+36 -36
View File
@@ -114,8 +114,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
p = p->pLeft;
continue;
}
assert( op!=TK_REGISTER || p->op2!=TK_COLLATE );
if( op==TK_COLLATE ){
if( op==TK_COLLATE || (op==TK_REGISTER && p->op2==TK_COLLATE) ){
pColl = sqlite3GetCollSeq(pParse, ENC(db), 0, p->u.zToken);
break;
}
@@ -597,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 );
@@ -667,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{
@@ -735,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{
@@ -835,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;
@@ -855,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);
@@ -865,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);
}
@@ -1176,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;
}
@@ -1279,6 +1277,7 @@ int sqlite3ExprIsInteger(Expr *p, int *pValue){
case TK_UMINUS: {
int v;
if( sqlite3ExprIsInteger(p->pLeft, &v) ){
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;
@@ -3504,6 +3503,7 @@ static void exprCodeBetween(
compRight.pLeft = &exprX;
compRight.pRight = pExpr->x.pList->a[1].pExpr;
exprX.iTable = sqlite3ExprCodeTemp(pParse, &exprX, &regFree1);
exprX.op2 = exprX.op;
exprX.op = TK_REGISTER;
if( jumpIfTrue ){
sqlite3ExprIfTrue(pParse, &exprAnd, dest, jumpIfNull);
@@ -3819,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;
}
@@ -4034,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.
@@ -4129,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);
}
}
}
}
+9 -6
View File
@@ -1522,9 +1522,9 @@ static void groupConcatFinalize(sqlite3_context *context){
StrAccum *pAccum;
pAccum = sqlite3_aggregate_context(context, 0);
if( pAccum ){
if( pAccum->tooBig ){
if( pAccum->accError==STRACCUM_TOOBIG ){
sqlite3_result_error_toobig(context);
}else if( pAccum->mallocFailed ){
}else if( pAccum->accError==STRACCUM_NOMEM ){
sqlite3_result_error_nomem(context);
}else{
sqlite3_result_text(context, sqlite3StrAccumFinish(pAccum), -1,
@@ -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
);
+5 -3
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;
@@ -2461,7 +2463,7 @@ static int openDatabase(
db->nextAutovac = -1;
db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
#endif
+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
+65 -46
View File
@@ -453,6 +453,13 @@ struct PagerSavepoint {
#endif
};
/*
** Bits of the Pager.doNotSpill flag. See further description below.
*/
#define SPILLFLAG_OFF 0x01 /* Never spill cache. Set via pragma */
#define SPILLFLAG_ROLLBACK 0x02 /* Current rolling back, so do not spill */
#define SPILLFLAG_NOSYNC 0x04 /* Spill is ok, but do not sync */
/*
** A open page cache is an instance of struct Pager. A description of
** some of the more important member variables follows:
@@ -519,19 +526,21 @@ struct PagerSavepoint {
** journal file from being successfully finalized, the setMaster flag
** is cleared anyway (and the pager will move to ERROR state).
**
** doNotSpill, doNotSyncSpill
** doNotSpill
**
** These two boolean variables control the behavior of cache-spills
** (calls made by the pcache module to the pagerStress() routine to
** write cached data to the file-system in order to free up memory).
** This variables control the behavior of cache-spills (calls made by
** the pcache module to the pagerStress() routine to write cached data
** to the file-system in order to free up memory).
**
** When doNotSpill is non-zero, writing to the database from pagerStress()
** is disabled altogether. This is done in a very obscure case that
** When bits SPILLFLAG_OFF or SPILLFLAG_ROLLBACK of doNotSpill are set,
** writing to the database from pagerStress() is disabled altogether.
** The SPILLFLAG_ROLLBACK case is done in a very obscure case that
** comes up during savepoint rollback that requires the pcache module
** to allocate a new page to prevent the journal file from being written
** while it is being traversed by code in pager_playback().
** while it is being traversed by code in pager_playback(). The SPILLFLAG_OFF
** case is a user preference.
**
** If doNotSyncSpill is non-zero, writing to the database from pagerStress()
** If the SPILLFLAG_NOSYNC bit is set, writing to the database from pagerStress()
** is permitted, but syncing the journal file is not. This flag is set
** by sqlite3PagerWrite() when the file-system sector-size is larger than
** the database page-size in order to prevent a journal sync from happening
@@ -635,7 +644,6 @@ struct Pager {
u8 changeCountDone; /* Set after incrementing the change-counter */
u8 setMaster; /* True if a m-j name has been written to jrnl */
u8 doNotSpill; /* Do not spill the cache when non-zero */
u8 doNotSyncSpill; /* Do not do a spill that requires jrnl sync */
u8 subjInMemory; /* True to use in-memory sub-journals */
Pgno dbSize; /* Number of pages in the database */
Pgno dbOrigSize; /* dbSize before the current transaction */
@@ -1014,13 +1022,17 @@ static char *print_pager_state(Pager *p){
** PagerSavepoint.pInSavepoint.
*/
static int subjRequiresPage(PgHdr *pPg){
Pgno pgno = pPg->pgno;
Pager *pPager = pPg->pPager;
PagerSavepoint *p;
Pgno pgno;
int i;
for(i=0; i<pPager->nSavepoint; i++){
PagerSavepoint *p = &pPager->aSavepoint[i];
if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
return 1;
if( pPager->nSavepoint ){
pgno = pPg->pgno;
for(i=0; i<pPager->nSavepoint; i++){
p = &pPager->aSavepoint[i];
if( p->nOrig>=pgno && 0==sqlite3BitvecTest(p->pInSavepoint, pgno) ){
return 1;
}
}
}
return 0;
@@ -2295,11 +2307,11 @@ static int pager_playback_one_page(
** requiring a journal-sync before it is written.
*/
assert( isSavepnt );
assert( pPager->doNotSpill==0 );
pPager->doNotSpill++;
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)==0 );
pPager->doNotSpill |= SPILLFLAG_ROLLBACK;
rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1);
assert( pPager->doNotSpill==1 );
pPager->doNotSpill--;
assert( (pPager->doNotSpill & SPILLFLAG_ROLLBACK)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_ROLLBACK;
if( rc!=SQLITE_OK ) return rc;
pPg->flags &= ~PGHDR_NEED_READ;
sqlite3PcacheMakeDirty(pPg);
@@ -2866,12 +2878,6 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
assert( pPager->eState>=PAGER_READER && !MEMDB );
assert( isOpen(pPager->fd) );
if( NEVER(!isOpen(pPager->fd)) ){
assert( pPager->tempFile );
memset(pPg->pData, 0, pPager->pageSize);
return SQLITE_OK;
}
#ifndef SQLITE_OMIT_WAL
if( iFrame ){
/* Try to pull the page from the write-ahead log. */
@@ -3404,9 +3410,12 @@ void sqlite3PagerShrink(Pager *pPager){
}
/*
** Adjust the robustness of the database to damage due to OS crashes
** or power failures by changing the number of syncs()s when writing
** the rollback journal. There are three levels:
** Adjust settings of the pager to those specified in the pgFlags parameter.
**
** The "level" in pgFlags & PAGER_SYNCHRONOUS_MASK sets the robustness
** of the database to damage due to OS crashes or power failures by
** changing the number of syncs()s when writing the journals.
** There are three levels:
**
** OFF sqlite3OsSync() is never called. This is the default
** for temporary and transient files.
@@ -3447,22 +3456,21 @@ void sqlite3PagerShrink(Pager *pPager){
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
void sqlite3PagerSetSafetyLevel(
void sqlite3PagerSetFlags(
Pager *pPager, /* The pager to set safety level for */
int level, /* PRAGMA synchronous. 1=OFF, 2=NORMAL, 3=FULL */
int bFullFsync, /* PRAGMA fullfsync */
int bCkptFullFsync /* PRAGMA checkpoint_fullfsync */
unsigned pgFlags /* Various flags */
){
unsigned level = pgFlags & PAGER_SYNCHRONOUS_MASK;
assert( level>=1 && level<=3 );
pPager->noSync = (level==1 || pPager->tempFile) ?1:0;
pPager->fullSync = (level==3 && !pPager->tempFile) ?1:0;
if( pPager->noSync ){
pPager->syncFlags = 0;
pPager->ckptSyncFlags = 0;
}else if( bFullFsync ){
}else if( pgFlags & PAGER_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_FULL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else if( bCkptFullFsync ){
}else if( pgFlags & PAGER_CKPT_FULLFSYNC ){
pPager->syncFlags = SQLITE_SYNC_NORMAL;
pPager->ckptSyncFlags = SQLITE_SYNC_FULL;
}else{
@@ -3473,6 +3481,11 @@ void sqlite3PagerSetSafetyLevel(
if( pPager->fullSync ){
pPager->walSyncFlags |= WAL_SYNC_TRANSACTIONS;
}
if( pgFlags & PAGER_CACHESPILL ){
pPager->doNotSpill &= ~SPILLFLAG_OFF;
}else{
pPager->doNotSpill |= SPILLFLAG_OFF;
}
}
#endif
@@ -4373,13 +4386,14 @@ static int pagerStress(void *p, PgHdr *pPg){
assert( pPg->pPager==pPager );
assert( pPg->flags&PGHDR_DIRTY );
/* The doNotSyncSpill flag is set during times when doing a sync of
/* The doNotSpill NOSYNC bit is set during times when doing a sync of
** journal (and adding a new header) is not allowed. This occurs
** during calls to sqlite3PagerWrite() while trying to journal multiple
** pages belonging to the same sector.
**
** The doNotSpill flag inhibits all cache spilling regardless of whether
** or not a sync is required. This is set during a rollback.
** The doNotSpill ROLLBACK and OFF bits inhibits all cache spilling
** regardless of whether or not a sync is required. This is set during
** a rollback or by user request, respectively.
**
** Spilling is also prohibited when in an error state since that could
** lead to database corruption. In the current implementaton it
@@ -4389,8 +4403,13 @@ static int pagerStress(void *p, PgHdr *pPg){
** test for the error state as a safeguard against future changes.
*/
if( NEVER(pPager->errCode) ) return SQLITE_OK;
if( pPager->doNotSpill ) return SQLITE_OK;
if( pPager->doNotSyncSpill && (pPg->flags & PGHDR_NEED_SYNC)!=0 ){
testcase( pPager->doNotSpill & SPILLFLAG_ROLLBACK );
testcase( pPager->doNotSpill & SPILLFLAG_OFF );
testcase( pPager->doNotSpill & SPILLFLAG_NOSYNC );
if( pPager->doNotSpill
&& ((pPager->doNotSpill & (SPILLFLAG_ROLLBACK|SPILLFLAG_OFF))!=0
|| (pPg->flags & PGHDR_NEED_SYNC)!=0)
){
return SQLITE_OK;
}
@@ -5212,19 +5231,19 @@ int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_ACQUIRE_XXX flags */
int flags /* PAGER_GET_XXX flags */
){
int rc = SQLITE_OK;
PgHdr *pPg = 0;
u32 iFrame = 0; /* Frame to read from WAL file */
const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
const int noContent = (flags & PAGER_GET_NOCONTENT);
/* It is acceptable to use a read-only (mmap) page for any page except
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
** flag was specified by the caller. And so long as the db is not a
** temporary or in-memory database. */
const int bMmapOk = (pgno!=1 && USEFETCH(pPager)
&& (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
&& (pPager->eState==PAGER_READER || (flags & PAGER_GET_READONLY))
#ifdef SQLITE_HAS_CODEC
&& pPager->xCodec==0
#endif
@@ -5744,13 +5763,13 @@ int sqlite3PagerWrite(DbPage *pDbPage){
int ii; /* Loop counter */
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
/* Set the doNotSyncSpill flag to 1. This is because we cannot allow
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
** a journal header to be written between the pages journaled by
** this function.
*/
assert( !MEMDB );
assert( pPager->doNotSyncSpill==0 );
pPager->doNotSyncSpill++;
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
/* This trick assumes that both the page-size and sector-size are
** an integer power of 2. It sets variable pg1 to the identifier
@@ -5809,8 +5828,8 @@ int sqlite3PagerWrite(DbPage *pDbPage){
}
}
assert( pPager->doNotSyncSpill==1 );
pPager->doNotSyncSpill--;
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
}else{
rc = pager_write(pDbPage);
}
+15 -3
View File
@@ -81,8 +81,20 @@ typedef struct PgHdr DbPage;
/*
** Flags that make up the mask passed to sqlite3PagerAcquire().
*/
#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
#define PAGER_GET_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_GET_READONLY 0x02 /* Read-only page is acceptable */
/*
** Flags for sqlite3PagerSetFlags()
*/
#define PAGER_SYNCHRONOUS_OFF 0x01 /* PRAGMA synchronous=OFF */
#define PAGER_SYNCHRONOUS_NORMAL 0x02 /* PRAGMA synchronous=NORMAL */
#define PAGER_SYNCHRONOUS_FULL 0x03 /* PRAGMA synchronous=FULL */
#define PAGER_SYNCHRONOUS_MASK 0x03 /* Mask for three values above */
#define PAGER_FULLFSYNC 0x04 /* PRAGMA fullfsync=ON */
#define PAGER_CKPT_FULLFSYNC 0x08 /* PRAGMA checkpoint_fullfsync=ON */
#define PAGER_CACHESPILL 0x10 /* PRAGMA cache_spill=ON */
#define PAGER_FLAGS_MASK 0x1c /* All above except SYNCHRONOUS */
/*
** The remainder of this file contains the declarations of the functions
@@ -110,7 +122,7 @@ int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
void sqlite3PagerShrink(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
void sqlite3PagerSetFlags(Pager*,unsigned);
int sqlite3PagerLockingMode(Pager *, int);
int sqlite3PagerSetJournalMode(Pager *, int);
int sqlite3PagerGetJournalMode(Pager*);
+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];
+1
View File
@@ -765,6 +765,7 @@ static sqlite3_pcache_page *pcache1Fetch(
if( pCache->nPage>=pCache->nHash && pcache1ResizeHash(pCache) ){
goto fetch_out;
}
assert( pCache->nHash>0 && pCache->apHash );
/* Step 4. Try to recycle a page. */
if( pCache->bPurgeable && pGroup->pLruTail && (
+38 -16
View File
@@ -158,6 +158,36 @@ static void returnSingleInt(Parse *pParse, const char *zLabel, i64 value){
sqlite3VdbeAddOp2(v, OP_ResultRow, mem, 1);
}
/*
** Set the safety_level and pager flags for pager iDb. Or if iDb<0
** set these values for all pagers.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
static void setAllPagerFlags(sqlite3 *db){
if( db->autoCommit ){
Db *pDb = db->aDb;
int n = db->nDb;
assert( SQLITE_FullFSync==PAGER_FULLFSYNC );
assert( SQLITE_CkptFullFSync==PAGER_CKPT_FULLFSYNC );
assert( SQLITE_CacheSpill==PAGER_CACHESPILL );
assert( (PAGER_FULLFSYNC | PAGER_CKPT_FULLFSYNC | PAGER_CACHESPILL)
== PAGER_FLAGS_MASK );
assert( (pDb->safety_level & PAGER_SYNCHRONOUS_MASK)==pDb->safety_level );
while( (n--) > 0 ){
if( pDb->pBt ){
sqlite3BtreeSetPagerFlags(pDb->pBt,
pDb->safety_level | (db->flags & PAGER_FLAGS_MASK) );
}
pDb++;
}
}
}
#else
# define setAllPagerFlags(X) /* no-op */
#endif
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
/*
** Check to see if zRight and zLeft refer to a pragma that queries
@@ -176,6 +206,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "legacy_file_format", SQLITE_LegacyFileFmt },
{ "fullfsync", SQLITE_FullFSync },
{ "checkpoint_fullfsync", SQLITE_CkptFullFSync },
{ "cache_spill", SQLITE_CacheSpill },
{ "reverse_unordered_selects", SQLITE_ReverseOrder },
{ "query_only", SQLITE_QueryOnly },
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -630,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);
@@ -764,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--){
@@ -778,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);
@@ -966,6 +999,7 @@ void sqlite3Pragma(
"Safety level may not be changed inside a transaction");
}else{
pDb->safety_level = getSafetyLevel(zRight,0,1)+1;
setAllPagerFlags(db);
}
}
}else
@@ -973,8 +1007,7 @@ void sqlite3Pragma(
#ifndef SQLITE_OMIT_FLAG_PRAGMAS
if( flagPragma(pParse, zLeft, zRight) ){
/* The flagPragma() subroutine also generates any necessary code
** there is nothing more to do here */
setAllPagerFlags(db);
}else
#endif /* SQLITE_OMIT_FLAG_PRAGMAS */
@@ -1805,17 +1838,6 @@ void sqlite3Pragma(
{/* Empty ELSE clause */}
/*
** Reset the safety level, in case the fullfsync flag or synchronous
** setting changed.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
if( db->autoCommit ){
sqlite3BtreeSetSafetyLevel(pDb->pBt, pDb->safety_level,
(db->flags&SQLITE_FullFSync)!=0,
(db->flags&SQLITE_CkptFullFSync)!=0);
}
#endif
pragma_out:
sqlite3DbFree(db, zLeft);
sqlite3DbFree(db, zRight);
+14 -17
View File
@@ -359,7 +359,7 @@ void sqlite3VXPrintf(
nOut = precision + 10;
zOut = zExtra = sqlite3Malloc( nOut );
if( zOut==0 ){
pAccum->mallocFailed = 1;
pAccum->accError = STRACCUM_NOMEM;
return;
}
}
@@ -471,7 +471,7 @@ void sqlite3VXPrintf(
if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){
bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 );
if( bufpt==0 ){
pAccum->mallocFailed = 1;
pAccum->accError = STRACCUM_NOMEM;
return;
}
}
@@ -606,7 +606,7 @@ void sqlite3VXPrintf(
if( n>etBUFSIZE ){
bufpt = zExtra = sqlite3Malloc( n );
if( bufpt==0 ){
pAccum->mallocFailed = 1;
pAccum->accError = STRACCUM_NOMEM;
return;
}
}else{
@@ -684,22 +684,20 @@ void sqlite3VXPrintf(
*/
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( z!=0 || N==0 );
if( p->tooBig | p->mallocFailed ){
testcase(p->tooBig);
testcase(p->mallocFailed);
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
return;
}
assert( p->zText!=0 || p->nChar==0 );
if( N<0 ){
if( N<=0 ){
if( N==0 || z[0]==0 ) return;
N = sqlite3Strlen30(z);
}
if( N==0 || NEVER(z==0) ){
return;
}
if( p->nChar+N >= p->nAlloc ){
char *zNew;
if( !p->useMalloc ){
p->tooBig = 1;
p->accError = STRACCUM_TOOBIG;
N = p->nAlloc - p->nChar - 1;
if( N<=0 ){
return;
@@ -710,7 +708,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
szNew += N + 1;
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
p->tooBig = 1;
p->accError = STRACCUM_TOOBIG;
return;
}else{
p->nAlloc = (int)szNew;
@@ -724,7 +722,7 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
p->mallocFailed = 1;
p->accError = STRACCUM_NOMEM;
sqlite3StrAccumReset(p);
return;
}
@@ -752,7 +750,7 @@ char *sqlite3StrAccumFinish(StrAccum *p){
if( p->zText ){
memcpy(p->zText, p->zBase, p->nChar+1);
}else{
p->mallocFailed = 1;
p->accError = STRACCUM_NOMEM;
}
}
}
@@ -783,8 +781,7 @@ void sqlite3StrAccumInit(StrAccum *p, char *zBase, int n, int mx){
p->nAlloc = n;
p->mxAlloc = mx;
p->useMalloc = 1;
p->tooBig = 0;
p->mallocFailed = 0;
p->accError = 0;
}
/*
@@ -801,7 +798,7 @@ char *sqlite3VMPrintf(sqlite3 *db, const char *zFormat, va_list ap){
acc.db = db;
sqlite3VXPrintf(&acc, 1, zFormat, ap);
z = sqlite3StrAccumFinish(&acc);
if( acc.mallocFailed ){
if( acc.accError==STRACCUM_NOMEM ){
db->mallocFailed = 1;
}
return z;
+14 -37
View File
@@ -28,24 +28,11 @@ static SQLITE_WSD struct sqlite3PrngType {
} sqlite3Prng;
/*
** Get a single 8-bit random value from the RC4 PRNG. The Mutex
** must be held while executing this routine.
**
** Why not just use a library random generator like lrand48() for this?
** Because the OP_NewRowid opcode in the VDBE depends on having a very
** good source of random numbers. The lrand48() library function may
** well be good enough. But maybe not. Or maybe lrand48() has some
** subtle problems on some systems that could cause problems. It is hard
** to know. To minimize the risk of problems due to bad lrand48()
** implementations, SQLite uses this random number generator based
** on RC4, which we know works very well.
**
** (Later): Actually, OP_NewRowid does not depend on a good source of
** randomness any more. But we will leave this code in all the same.
** Return N random bytes.
*/
static u8 randomByte(void){
void sqlite3_randomness(int N, void *pBuf){
unsigned char t;
unsigned char *zBuf = pBuf;
/* The "wsdPrng" macro will resolve to the pseudo-random number generator
** state vector. If writable static data is unsupported on the target,
@@ -60,6 +47,10 @@ static u8 randomByte(void){
# define wsdPrng sqlite3Prng
#endif
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
sqlite3_mutex_enter(mutex);
#endif
/* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does
@@ -88,28 +79,14 @@ static u8 randomByte(void){
wsdPrng.isInit = 1;
}
/* Generate and return single random byte
*/
wsdPrng.i++;
t = wsdPrng.s[wsdPrng.i];
wsdPrng.j += t;
wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
wsdPrng.s[wsdPrng.j] = t;
t += wsdPrng.s[wsdPrng.i];
return wsdPrng.s[t];
}
/*
** Return N random bytes.
*/
void sqlite3_randomness(int N, void *pBuf){
unsigned char *zBuf = pBuf;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_PRNG);
#endif
sqlite3_mutex_enter(mutex);
while( N-- ){
*(zBuf++) = randomByte();
wsdPrng.i++;
t = wsdPrng.s[wsdPrng.i];
wsdPrng.j += t;
wsdPrng.s[wsdPrng.i] = wsdPrng.s[wsdPrng.j];
wsdPrng.s[wsdPrng.j] = t;
t += wsdPrng.s[wsdPrng.i];
*(zBuf++) = wsdPrng.s[t];
}
sqlite3_mutex_leave(mutex);
}
+29 -21
View File
@@ -55,7 +55,7 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** column reference is so that the column reference will be recognized as
** usable by indices within the WHERE clause processing logic.
**
** Hack: The TK_AS operator is inhibited if zType[0]=='G'. This means
** The TK_AS operator is inhibited if zType[0]=='G'. This means
** that in a GROUP BY clause, the expression is evaluated twice. Hence:
**
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x
@@ -65,8 +65,9 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){
** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5
**
** The result of random()%5 in the GROUP BY clause is probably different
** from the result in the result-set. We might fix this someday. Or
** then again, we might not...
** from the result in the result-set. On the other hand Standard SQL does
** not allow the GROUP BY clause to contain references to result-set columns.
** So this should never come up in well-formed queries.
**
** If the reference is followed by a COLLATE operator, then make sure
** the COLLATE operator is preserved. For example:
@@ -128,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);
}
@@ -228,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;
@@ -396,10 +397,16 @@ static int lookupName(
** forms the result set entry ("a+b" in the example) and return immediately.
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
**
** The ability to use an output result-set column in the WHERE, GROUP BY,
** or HAVING clauses, or as part of a larger expression in the ORDRE BY
** clause is not standard SQL. This is a (goofy) SQLite extension, that
** is supported for backwards compatibility only. TO DO: Issue a warning
** on sqlite3_log() whenever the capability is used.
*/
if( (pEList = pNC->pEList)!=0
&& zTab==0
&& ((pNC->ncFlags & NC_AsMaybe)==0 || cnt==0)
&& cnt==0
){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
@@ -584,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 ){
@@ -961,7 +968,7 @@ static int resolveCompoundOrderBy(
/*
** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
** the SELECT statement pSelect. If any term is reference to a
** result set expression (as determined by the ExprList.a.iCol field)
** result set expression (as determined by the ExprList.a.iOrderByCol field)
** then convert that term into a copy of the corresponding result set
** column.
**
@@ -1009,7 +1016,7 @@ int sqlite3ResolveOrderGroupBy(
** If the order-by term is an integer I between 1 and N (where N is the
** number of columns in the result set of the SELECT) then the expression
** in the resolution is a copy of the I-th result-set expression. If
** the order-by term is an identify that corresponds to the AS-name of
** the order-by term is an identifier that corresponds to the AS-name of
** a result-set expression, then the term resolves to a copy of the
** result-set expression. Otherwise, the expression is resolved in
** the usual way - using sqlite3ResolveExprNames().
@@ -1035,16 +1042,19 @@ static int resolveOrderGroupBy(
pParse = pNC->pParse;
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
Expr *pE = pItem->pExpr;
iCol = resolveAsName(pParse, pSelect->pEList, pE);
if( iCol>0 ){
/* If an AS-name match is found, mark this ORDER BY column as being
** a copy of the iCol-th result-set column. The subsequent call to
** sqlite3ResolveOrderGroupBy() will convert the expression to a
** copy of the iCol-th result-set expression. */
pItem->iOrderByCol = (u16)iCol;
continue;
Expr *pE2 = sqlite3ExprSkipCollate(pE);
if( zType[0]!='G' ){
iCol = resolveAsName(pParse, pSelect->pEList, pE2);
if( iCol>0 ){
/* If an AS-name match is found, mark this ORDER BY column as being
** a copy of the iCol-th result-set column. The subsequent call to
** sqlite3ResolveOrderGroupBy() will convert the expression to a
** copy of the iCol-th result-set expression. */
pItem->iOrderByCol = (u16)iCol;
continue;
}
}
if( sqlite3ExprIsInteger(sqlite3ExprSkipCollate(pE), &iCol) ){
if( sqlite3ExprIsInteger(pE2, &iCol) ){
/* The ORDER BY term is an integer constant. Again, set the column
** number so that sqlite3ResolveOrderGroupBy() will convert the
** order-by term to a copy of the result-set expression */
@@ -1187,7 +1197,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
return WRC_Abort;
}
/* Add the expression list to the name-context before parsing the
/* Add the output column list to the name-context before parsing the
** other expressions in the SELECT statement. This is so that
** expressions in the WHERE clause (etc.) can refer to expressions by
** aliases in the result set.
@@ -1196,10 +1206,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
** re-evaluated for each reference to it.
*/
sNC.pEList = p->pEList;
sNC.ncFlags |= NC_AsMaybe;
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
sNC.ncFlags &= ~NC_AsMaybe;
/* The ORDER BY and GROUP BY clauses may not refer to terms in
** outer queries
+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;
+14 -10
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;
@@ -1717,7 +1721,7 @@ static char *csv_read_one_field(CSVReader *p){
}
if( (c==cSep && pc==cQuote)
|| (c=='\n' && pc==cQuote)
|| (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote)
|| (c=='\n' && pc=='\r' && p->n>=2 && p->z[p->n-2]==cQuote)
|| (c==EOF && pc==cQuote)
){
do{ p->n--; }while( p->z[p->n]!=cQuote );
@@ -2902,6 +2906,7 @@ static int process_input(struct callback_data *p, FILE *in){
if( nSql==0 ){
int i;
for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
assert( nAlloc>0 && zSql!=0 );
memcpy(zSql, zLine+i, nLine+1-i);
startline = lineno;
nSql = nLine-i;
@@ -3187,7 +3192,6 @@ int main(int argc, char **argv){
stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
int j, c;
const char *zSize;
sqlite3_int64 szHeap;
+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))
+104 -96
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 */
@@ -972,32 +984,33 @@ struct sqlite3 {
*/
#define SQLITE_VdbeTrace 0x00000001 /* True to trace VDBE execution */
#define SQLITE_InternChanges 0x00000002 /* Uncommitted Hash table changes */
#define SQLITE_FullColNames 0x00000004 /* Show full column names on SELECT */
#define SQLITE_ShortColNames 0x00000008 /* Show short columns names */
#define SQLITE_CountRows 0x00000010 /* Count rows changed by INSERT, */
#define SQLITE_FullFSync 0x00000004 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00000008 /* Use full fsync for checkpoint */
#define SQLITE_CacheSpill 0x00000010 /* OK to spill pager cache */
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_NullCallback 0x00000020 /* Invoke the callback once if the */
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_SqlTrace 0x00000040 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00000080 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00000100 /* OK to update SQLITE_MASTER */
#define SQLITE_VdbeAddopTrace 0x00000200 /* Trace sqlite3VdbeAddOp() calls */
#define SQLITE_IgnoreChecks 0x00000400 /* Do not enforce check constraints */
#define SQLITE_ReadUncommitted 0x0000800 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt 0x00001000 /* Create new databases in format 1 */
#define SQLITE_FullFSync 0x00002000 /* Use full fsync on the backend */
#define SQLITE_CkptFullFSync 0x00004000 /* Use full fsync for checkpoint */
#define SQLITE_RecoveryMode 0x00008000 /* Ignore schema errors */
#define SQLITE_ReverseOrder 0x00010000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00020000 /* Enable recursive triggers */
#define SQLITE_ForeignKeys 0x00040000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x00080000 /* Enable automatic indexes */
#define SQLITE_PreferBuiltin 0x00100000 /* Preference to built-in funcs */
#define SQLITE_LoadExtension 0x00200000 /* Enable load_extension */
#define SQLITE_EnableTrigger 0x00400000 /* True to enable triggers */
#define SQLITE_DeferFKs 0x00800000 /* Defer all FK constraints */
#define SQLITE_QueryOnly 0x01000000 /* Disable database changes */
#define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */
#define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */
#define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */
#define SQLITE_VdbeAddopTrace 0x00001000 /* Trace sqlite3VdbeAddOp() calls */
#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */
#define SQLITE_ReadUncommitted 0x0004000 /* For shared-cache mode */
#define SQLITE_LegacyFileFmt 0x00008000 /* Create new databases in format 1 */
#define SQLITE_RecoveryMode 0x00010000 /* Ignore schema errors */
#define SQLITE_ReverseOrder 0x00020000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00040000 /* Enable recursive triggers */
#define SQLITE_ForeignKeys 0x00080000 /* Enforce foreign key constraints */
#define SQLITE_AutoIndex 0x00100000 /* Enable automatic indexes */
#define SQLITE_PreferBuiltin 0x00200000 /* Preference to built-in funcs */
#define SQLITE_LoadExtension 0x00400000 /* Enable load_extension */
#define SQLITE_EnableTrigger 0x00800000 /* True to enable triggers */
#define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */
#define SQLITE_QueryOnly 0x02000000 /* Disable database changes */
/*
@@ -1050,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 */
@@ -1087,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
@@ -1122,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}
/*
@@ -1549,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
};
@@ -1562,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 */
};
/*
@@ -1712,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 */
@@ -1726,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
@@ -1745,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 */
@@ -1756,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
@@ -1786,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
@@ -1795,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)
@@ -2006,7 +2011,7 @@ struct SrcList {
struct NameContext {
Parse *pParse; /* The parser */
SrcList *pSrcList; /* One or more tables used to resolve names */
ExprList *pEList; /* Optional list of named expressions */
ExprList *pEList; /* Optional list of result-set columns */
AggInfo *pAggInfo; /* Information about aggregates at this level */
NameContext *pNext; /* Next outer name context. NULL for outermost */
int nRef; /* Number of names resolved by this context */
@@ -2021,9 +2026,7 @@ struct NameContext {
#define NC_HasAgg 0x02 /* One or more aggregate functions seen */
#define NC_IsCheck 0x04 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
#define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
** if no other resolution is available */
#define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */
#define NC_PartIdx 0x10 /* True if resolving a partial index WHERE */
/*
** An instance of the following structure contains all information
@@ -2426,10 +2429,11 @@ struct StrAccum {
int nChar; /* Length of the string so far */
int nAlloc; /* Amount of space allocated in zText */
int mxAlloc; /* Maximum allowed string length */
u8 mallocFailed; /* Becomes true if any memory allocation fails */
u8 useMalloc; /* 0: none, 1: sqlite3DbMalloc, 2: sqlite3_malloc */
u8 tooBig; /* Becomes true if string size exceeds limits */
u8 accError; /* STRACCUM_NOMEM or STRACCUM_TOOBIG */
};
#define STRACCUM_NOMEM 1
#define STRACCUM_TOOBIG 2
/*
** A pointer to this structure is used to communicate information
@@ -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
*/
@@ -3154,13 +3161,14 @@ void sqlite3AutoLoadExtensions(sqlite3*);
#else
void sqlite3VtabClear(sqlite3 *db, Table*);
void sqlite3VtabDisconnect(sqlite3 *db, Table *p);
int sqlite3VtabSync(sqlite3 *db, char **);
int sqlite3VtabSync(sqlite3 *db, Vdbe*);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
void sqlite3VtabLock(VTable *);
void sqlite3VtabUnlock(VTable *);
void sqlite3VtabUnlockList(sqlite3*);
int sqlite3VtabSavepoint(sqlite3 *, int, int);
void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*);
VTable *sqlite3GetVTable(sqlite3*, Table*);
# define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0)
#endif
@@ -3195,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
+57 -70
View File
@@ -497,19 +497,6 @@ static int checkSavepointCount(sqlite3 *db){
}
#endif
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
** in memory obtained from sqlite3DbMalloc).
*/
static void importVtabErrMsg(Vdbe *p, sqlite3_vtab *pVtab){
sqlite3 *db = p->db;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
}
/*
** Execute as much of a VDBE program as we can then return.
@@ -588,7 +575,7 @@ int sqlite3VdbeExec(
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
if( db->xProgress ){
assert( 0 < db->nProgressOps );
nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1];
nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP];
if( nProgressLimit==0 ){
nProgressLimit = db->nProgressOps;
}else{
@@ -651,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);
@@ -662,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
@@ -778,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);
@@ -990,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++;
@@ -1059,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;
@@ -1144,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
@@ -1418,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++){
@@ -1449,8 +1436,8 @@ case OP_Function: {
sqlite3VdbeMemMove(&ctx.s, pOut);
MemSetTypeFlag(&ctx.s, MEM_Null);
ctx.isError = 0;
if( ctx.pFunc->flags & SQLITE_FUNC_NEEDCOLL ){
ctx.fErrorOrAux = 0;
if( ctx.pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
assert( pOp>aOp );
assert( pOp[-1].p4type==P4_COLLSEQ );
assert( pOp[-1].opcode==OP_CollSeq );
@@ -1460,11 +1447,6 @@ case OP_Function: {
(*ctx.pFunc->xFunc)(&ctx, n, apVal); /* IMP: R-24505-23230 */
lastRowid = db->lastRowid;
/* If any auxiliary data functions have been called by this user function,
** immediately call the destructor for any non-static values.
*/
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
if( db->mallocFailed ){
/* Even though a malloc() has failed, the implementation of the
** user function may have called an sqlite3_result_XXX() function
@@ -1476,9 +1458,12 @@ case OP_Function: {
}
/* If the function returned an error, throw an exception */
if( ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
rc = ctx.isError;
if( ctx.fErrorOrAux ){
if( ctx.isError ){
sqlite3SetString(&p->zErrMsg, db, "%s", sqlite3_value_text(&ctx.s));
rc = ctx.isError;
}
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
}
/* Copy the result of the function into register P3 */
@@ -1850,12 +1835,12 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** then the result is always NULL.
** The jump is taken if the SQLITE_JUMPIFNULL bit is set.
*/
if( pOp->p5 & SQLITE_STOREP2 ){
if( pOp->p5 & SQLITE_JUMPIFNULL ){
pc = pOp->p2-1;
}else if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
MemSetTypeFlag(pOut, MEM_Null);
REGISTER_TRACE(pOp->p2, pOut);
}else if( pOp->p5 & SQLITE_JUMPIFNULL ){
pc = pOp->p2-1;
}
break;
}
@@ -1954,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++){
@@ -2209,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;
@@ -2507,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);
@@ -2568,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];
@@ -2634,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;
@@ -3214,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 );
@@ -3751,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. */
@@ -3954,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);
}
@@ -4352,7 +4337,7 @@ case OP_Rowid: { /* out2-prerelease */
pModule = pVtab->pModule;
assert( pModule->xRowid );
rc = pModule->xRowid(pC->pVtabCursor, &v);
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}else{
assert( pC->pCursor!=0 );
@@ -4440,7 +4425,7 @@ case OP_Sort: { /* jump */
sqlite3_sort_count++;
sqlite3_search_count--;
#endif
p->aCounter[SQLITE_STMTSTATUS_SORT-1]++;
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
/* Fall through into OP_Rewind */
}
/* Opcode: Rewind P1 P2 * * *
@@ -4519,7 +4504,7 @@ case OP_Next: { /* jump */
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<=ArraySize(p->aCounter) );
assert( pOp->p5<ArraySize(p->aCounter) );
pC = p->apCsr[pOp->p1];
if( pC==0 ){
break; /* See ticket #2273 */
@@ -4529,7 +4514,7 @@ case OP_Next: { /* jump */
assert( pOp->opcode==OP_SorterNext );
rc = sqlite3VdbeSorterNext(db, pC, &res);
}else{
res = 1;
/* res = 1; // Always initialized by the xAdvance() call */
assert( pC->deferredMoveto==0 );
assert( pC->pCursor );
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
@@ -4540,7 +4525,7 @@ case OP_Next: { /* jump */
pC->cacheStatus = CACHE_STALE;
if( res==0 ){
pc = pOp->p2 - 1;
if( pOp->p5 ) p->aCounter[pOp->p5-1]++;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
@@ -4608,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 );
@@ -4816,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)
@@ -5016,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 );
@@ -5440,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;
@@ -5451,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 );
@@ -5487,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);
@@ -5745,7 +5731,7 @@ case OP_VBegin: {
VTable *pVTab;
pVTab = pOp->p4.pVtab;
rc = sqlite3VtabBegin(db, pVTab);
if( pVTab ) importVtabErrMsg(p, pVTab->pVtab);
if( pVTab ) sqlite3VtabImportErrmsg(p, pVTab->pVtab);
break;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -5796,7 +5782,7 @@ case OP_VOpen: {
pModule = (sqlite3_module *)pVtab->pModule;
assert(pVtab && pModule);
rc = pModule->xOpen(pVtab, &pVtabCursor);
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
if( SQLITE_OK==rc ){
/* Initialize sqlite3_vtab_cursor base class */
pVtabCursor->pVtab = pVtab;
@@ -5874,7 +5860,7 @@ case OP_VFilter: { /* jump */
p->inVtabMethod = 1;
rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg);
p->inVtabMethod = 0;
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pVtabCursor);
}
@@ -5904,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 ){
@@ -5925,7 +5911,7 @@ case OP_VColumn: {
MemSetTypeFlag(&sContext.s, MEM_Null);
rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2);
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
if( sContext.isError ){
rc = sContext.isError;
}
@@ -5978,7 +5964,7 @@ case OP_VNext: { /* jump */
p->inVtabMethod = 1;
rc = pModule->xNext(pCur->pVtabCursor);
p->inVtabMethod = 0;
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
}
@@ -6015,7 +6001,7 @@ case OP_VRename: {
rc = sqlite3VdbeChangeEncoding(pName, SQLITE_UTF8);
if( rc==SQLITE_OK ){
rc = pVtab->pModule->xRename(pVtab, pName->z);
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
p->expired = 0;
}
break;
@@ -6077,7 +6063,7 @@ case OP_VUpdate: {
db->vtabOnConflict = pOp->p5;
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
db->vtabOnConflict = vtabOnConflict;
importVtabErrMsg(p, pVtab);
sqlite3VtabImportErrmsg(p, pVtab);
if( rc==SQLITE_OK && pOp->p1 ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
db->lastRowid = lastRowid = rowid;
@@ -6242,7 +6228,8 @@ vdbe_error_halt:
** top. */
vdbe_return:
db->lastRowid = lastRowid;
p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1] += (int)nVmStep;
testcase( nVmStep>0 );
p->aCounter[SQLITE_STMTSTATUS_VM_STEP] += (int)nVmStep;
sqlite3VdbeLeave(p);
return rc;
+5 -4
View File
@@ -266,10 +266,11 @@ struct sqlite3_context {
Mem s; /* The return value is stored here */
Mem *pMem; /* Memory cell used to store aggregate context */
CollSeq *pColl; /* Collating sequence */
int isError; /* Error code returned by the function. */
int skipFlag; /* Skip skip accumulator loading if true */
int iOp; /* Instruction number of OP_Function */
Vdbe *pVdbe; /* The VM that owns this context */
int iOp; /* Instruction number of OP_Function */
int isError; /* Error code returned by the function. */
u8 skipFlag; /* Skip skip accumulator loading if true */
u8 fErrorOrAux; /* isError!=0 or pVdbe->pAuxData modified */
};
/*
@@ -345,7 +346,7 @@ struct Vdbe {
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
int iStatement; /* Statement number (or 0 if has not opened stmt) */
int aCounter[4]; /* Counters used by sqlite3_stmt_status() */
u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */
#ifndef SQLITE_OMIT_TRACE
i64 startTime; /* Time when query started - used for profiling */
#endif
+12 -3
View File
@@ -211,12 +211,14 @@ void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = SQLITE_ERROR;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
@@ -280,6 +282,7 @@ void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
}
void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
pCtx->isError = errCode;
pCtx->fErrorOrAux = 1;
if( pCtx->s.flags & MEM_Null ){
sqlite3VdbeMemSetStr(&pCtx->s, sqlite3ErrStr(errCode), -1,
SQLITE_UTF8, SQLITE_STATIC);
@@ -290,6 +293,7 @@ void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
void sqlite3_result_error_toobig(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
pCtx->fErrorOrAux = 1;
sqlite3VdbeMemSetStr(&pCtx->s, "string or blob too big", -1,
SQLITE_UTF8, SQLITE_STATIC);
}
@@ -299,6 +303,7 @@ void sqlite3_result_error_nomem(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
sqlite3VdbeMemSetNull(&pCtx->s);
pCtx->isError = SQLITE_NOMEM;
pCtx->fErrorOrAux = 1;
pCtx->s.db->mallocFailed = 1;
}
@@ -621,6 +626,10 @@ void sqlite3_set_auxdata(
pAuxData->iArg = iArg;
pAuxData->pNext = pVdbe->pAuxData;
pVdbe->pAuxData = pAuxData;
if( pCtx->fErrorOrAux==0 ){
pCtx->isError = 0;
pCtx->fErrorOrAux = 1;
}
}else if( pAuxData->xDelete ){
pAuxData->xDelete(pAuxData->pAux);
}
@@ -1289,7 +1298,7 @@ sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt){
*/
int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
Vdbe *pVdbe = (Vdbe*)pStmt;
int v = pVdbe->aCounter[op-1];
if( resetFlag ) pVdbe->aCounter[op-1] = 0;
return v;
u32 v = pVdbe->aCounter[op];
if( resetFlag ) pVdbe->aCounter[op] = 0;
return (int)v;
}
+17 -2
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);
}
}
@@ -1765,7 +1765,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){
** required, as an xSync() callback may add an attached database
** to the transaction.
*/
rc = sqlite3VtabSync(db, &p->zErrMsg);
rc = sqlite3VtabSync(db, p);
/* This loop determines (a) if the commit hook should be invoked and
** (b) how many database files have open write transactions, not
@@ -3304,3 +3304,18 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
v->expmask |= ((u32)1 << (iVar-1));
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
** in memory obtained from sqlite3_malloc) into a Vdbe.zErrMsg (text stored
** in memory obtained from sqlite3DbMalloc).
*/
void sqlite3VtabImportErrmsg(Vdbe *p, sqlite3_vtab *pVtab){
sqlite3 *db = p->db;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+298 -49
View File
@@ -799,34 +799,29 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
** if both values are integers.
*/
if( combined_flags&(MEM_Int|MEM_Real) ){
if( !(f1&(MEM_Int|MEM_Real)) ){
return 1;
}
if( !(f2&(MEM_Int|MEM_Real)) ){
return -1;
}
if( (f1 & f2 & MEM_Int)==0 ){
double r1, r2;
if( (f1&MEM_Real)==0 ){
r1 = (double)pMem1->u.i;
}else{
r1 = pMem1->r;
}
if( (f2&MEM_Real)==0 ){
r2 = (double)pMem2->u.i;
}else{
r2 = pMem2->r;
}
if( r1<r2 ) return -1;
if( r1>r2 ) return 1;
return 0;
}else{
assert( f1&MEM_Int );
assert( f2&MEM_Int );
double r1, r2;
if( (f1 & f2 & MEM_Int)!=0 ){
if( pMem1->u.i < pMem2->u.i ) return -1;
if( pMem1->u.i > pMem2->u.i ) return 1;
return 0;
}
if( (f1&MEM_Real)!=0 ){
r1 = pMem1->r;
}else if( (f1&MEM_Int)!=0 ){
r1 = (double)pMem1->u.i;
}else{
return 1;
}
if( (f2&MEM_Real)!=0 ){
r2 = pMem2->r;
}else if( (f2&MEM_Int)!=0 ){
r2 = (double)pMem2->u.i;
}else{
return -1;
}
if( r1<r2 ) return -1;
if( r1>r2 ) return 1;
return 0;
}
/* If one value is a string and the other is a blob, the string is less.
@@ -1006,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;
@@ -1034,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;
@@ -1056,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);
@@ -1073,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;
@@ -1090,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
@@ -1098,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;
@@ -1112,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
*/
+4 -7
View File
@@ -810,10 +810,9 @@ static void callFinaliser(sqlite3 *db, int offset){
** array. Return the error code for the first error that occurs, or
** SQLITE_OK if all xSync operations are successful.
**
** Set *pzErrmsg to point to a buffer that should be released using
** sqlite3DbFree() containing an error message, if one is available.
** If an error message is available, leave it in p->zErrMsg.
*/
int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
int sqlite3VtabSync(sqlite3 *db, Vdbe *p){
int i;
int rc = SQLITE_OK;
VTable **aVTrans = db->aVTrans;
@@ -824,9 +823,7 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
sqlite3_vtab *pVtab = aVTrans[i]->pVtab;
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
rc = x(pVtab);
sqlite3DbFree(db, *pzErrmsg);
*pzErrmsg = pVtab->zErrMsg;
pVtab->zErrMsg = 0;
sqlite3VtabImportErrmsg(p, pVtab);
}
}
db->aVTrans = aVTrans;
@@ -1016,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) ){
+292 -271
View File
@@ -90,6 +90,7 @@ struct WhereLevel {
int addrNxt; /* Jump here to start the next IN combination */
int addrCont; /* Jump here to continue with the next loop cycle */
int addrFirst; /* First instruction of interior of the loop */
int addrBody; /* Beginning of the body of this loop */
u8 iFrom; /* Which entry in the FROM clause */
u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
int p1, p2; /* Operands of the opcode used to ends the loop */
@@ -105,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 */
};
/*
@@ -184,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.
@@ -285,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 */
@@ -391,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
};
/*
@@ -1204,8 +1210,10 @@ static int isMatchOfColumn(
** a join, then transfer the appropriate markings over to derived.
*/
static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
pDerived->flags |= pBase->flags & EP_FromJoin;
pDerived->iRightJoinTable = pBase->iRightJoinTable;
if( pDerived ){
pDerived->flags |= pBase->flags & EP_FromJoin;
pDerived->iRightJoinTable = pBase->iRightJoinTable;
}
}
#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
@@ -1662,6 +1670,7 @@ static void exprAnalyze(
pNewExpr = sqlite3PExpr(pParse, ops[i],
sqlite3ExprDup(db, pExpr->pLeft, 0),
sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0);
transferJoinMarkings(pNewExpr, pExpr);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew==0 );
exprAnalyze(pSrc, pWC, idxNew);
@@ -1729,6 +1738,7 @@ static void exprAnalyze(
pNewExpr1 = sqlite3PExpr(pParse, TK_GE,
sqlite3ExprAddCollateToken(pParse,pNewExpr1,&sCollSeqName),
pStr1, 0);
transferJoinMarkings(pNewExpr1, pExpr);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew1==0 );
exprAnalyze(pSrc, pWC, idxNew1);
@@ -1736,6 +1746,7 @@ static void exprAnalyze(
pNewExpr2 = sqlite3PExpr(pParse, TK_LT,
sqlite3ExprAddCollateToken(pParse,pNewExpr2,&sCollSeqName),
pStr2, 0);
transferJoinMarkings(pNewExpr2, pExpr);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
testcase( idxNew2==0 );
exprAnalyze(pSrc, pWC, idxNew2);
@@ -1785,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
@@ -1825,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.
@@ -2393,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:
@@ -2403,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{
@@ -2550,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
@@ -2604,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
@@ -2720,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
@@ -2769,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 */
@@ -2781,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
@@ -2820,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 ){
@@ -3029,7 +3010,7 @@ static int codeAllEqualityTerms(
/* Evaluate the equality constraints
*/
assert( pIdx->nColumn>=nEq );
assert( zAff==0 || (int)strlen(zAff)>=nEq );
for(j=0; j<nEq; j++){
int r1;
pTerm = pLoop->aLTerm[j];
@@ -3121,7 +3102,8 @@ static char *explainIndexRange(sqlite3 *db, WhereLoop *pLoop, Table *pTab){
txt.db = db;
sqlite3StrAccumAppend(&txt, " (", 2);
for(i=0; i<nEq; i++){
explainAppendTerm(&txt, i, aCol[aiColumn[i]].zName, "=");
char *z = (i==pIndex->nColumn ) ? "rowid" : aCol[aiColumn[i]].zName;
explainAppendTerm(&txt, i, z, "=");
}
j = i;
@@ -3244,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;
@@ -3254,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;
@@ -3906,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.
@@ -3916,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;
@@ -3948,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;
@@ -3976,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;
}
@@ -3987,7 +3968,7 @@ static Bitmask codeOneLoopStart(
}
sqlite3ReleaseTempReg(pParse, iReleaseReg);
return newNotReady;
return pLevel->notReady;
}
#ifdef WHERETRACE_ENABLED
@@ -4088,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 ){
@@ -4197,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 */
@@ -4219,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;
}
@@ -4335,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
if( (pTerm->wtFlags & TERM_VNULL)!=0 && pSrc->pTab->aCol[iCol].notNull ){
continue; /* skip IS NOT NULL constraints on a NOT NULL column */
}
#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;
@@ -4397,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 ){
@@ -4432,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;
@@ -4480,6 +4483,7 @@ static Bitmask columnsInIndex(Index *pIdx){
int j;
for(j=pIdx->nColumn-1; j>=0; j--){
int x = pIdx->aiColumn[j];
assert( x>=0 );
testcase( x==BMS-1 );
testcase( x==BMS-2 );
if( x<BMS-1 ) m |= MASKBIT(x);
@@ -4558,6 +4562,7 @@ static int whereLoopAddBtree(
rSize = whereCost(pSrc->pTab->nRowEst);
rLogSize = estLog(rSize);
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
/* Automatic indexes */
if( !pBuilder->pOrSet
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
@@ -4592,6 +4597,7 @@ static int whereLoopAddBtree(
}
}
}
#endif /* SQLITE_OMIT_AUTOMATIC_INDEX */
/* Loop over all indices
*/
@@ -4658,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. */
@@ -4855,6 +4867,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
if( pWInfo->wctrlFlags & WHERE_AND_ONLY ) return SQLITE_OK;
pWCEnd = pWC->a + pWC->nTerm;
pNew = pBuilder->pNew;
memset(&sSum, 0, sizeof(sSum));
for(pTerm=pWC->a; pTerm<pWCEnd && rc==SQLITE_OK; pTerm++){
if( (pTerm->eOperator & WO_OR)!=0
@@ -5540,11 +5553,15 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->rRun = 33; /* 33==whereCost(10) */
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_None || pIdx->pPartIdxWhere!=0 ) continue;
assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 );
if( pIdx->onError==OE_None
|| pIdx->pPartIdxWhere!=0
|| pIdx->nColumn>ArraySize(pLoop->aLTermSpace)
) continue;
for(j=0; j<pIdx->nColumn; j++){
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
if( pTerm==0 ) break;
whereLoopResize(pWInfo->pParse->db, pLoop, j);
pLoop->aLTerm[j] = pTerm;
}
if( j!=pIdx->nColumn ) continue;
@@ -5899,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;
@@ -5981,11 +5998,6 @@ WhereInfo *sqlite3WhereBegin(
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
}
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel);
}else
#endif
if( pLoop->wsFlags & WHERE_INDEXED ){
Index *pIx = pLoop->u.btree.pIndex;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx);
@@ -6010,7 +6022,15 @@ WhereInfo *sqlite3WhereBegin(
notReady = ~(Bitmask)0;
for(ii=0; ii<nTabList; ii++){
pLevel = &pWInfo->a[ii];
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){
constructAutomaticIndex(pParse, &pWInfo->sWC,
&pTabList->a[pLevel->iFrom], notReady, pLevel);
if( db->mallocFailed ) goto whereBeginError;
}
#endif
explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags);
pLevel->addrBody = sqlite3VdbeCurrentAddr(v);
notReady = codeOneLoopStart(pWInfo, ii, notReady);
pWInfo->iContinue = pLevel->addrCont;
}
@@ -6130,9 +6150,10 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
int k, j, last;
VdbeOp *pOp;
pOp = sqlite3VdbeGetOp(v, pWInfo->iTop);
last = sqlite3VdbeCurrentAddr(v);
for(k=pWInfo->iTop; k<last; k++, pOp++){
k = pLevel->addrBody;
pOp = sqlite3VdbeGetOp(v, k);
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
for(j=0; j<pIdx->nColumn; j++){
+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
+28
View File
@@ -17,6 +17,8 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix collate2
#
# Tests are organised as follows:
#
@@ -693,4 +695,30 @@ do_test collate2-5.5 {
}
} {aa aa}
do_execsql_test 6.1 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES('b');
INSERT INTO t1 VALUES('B');
}
do_execsql_test 6.2 {
SELECT * FROM t1 WHERE x COLLATE nocase BETWEEN 'a' AND 'c';
} {b B}
do_execsql_test 6.3 {
SELECT * FROM t1 WHERE x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
} {b B}
do_execsql_test 6.4 {
SELECT * FROM t1
WHERE x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
} {b B}
do_execsql_test 6.5 {
SELECT * FROM t1 WHERE +x COLLATE nocase BETWEEN 'a' AND 'c';
} {b B}
do_execsql_test 6.6 {
SELECT * FROM t1 WHERE +x BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
} {b B}
do_execsql_test 6.7 {
SELECT * FROM t1
WHERE +x COLLATE nocase BETWEEN 'a' COLLATE nocase AND 'c' COLLATE nocase;
} {b B}
finish_test
+4 -2
View File
@@ -31,9 +31,11 @@ do_execsql_test 1.1 {
CREATE INDEX t1abc ON t1(a,b,c);
}
set idxroot [db one {SELECT rootpage FROM sqlite_master WHERE name = 't1abc'}]
# Corrupt the file
db close
hexio_write test.db [expr {3*512 - 15}] 888080807f
hexio_write test.db [expr {$idxroot*512 - 15}] 888080807f
sqlite3 db test.db
# Try to use the file.
@@ -58,7 +60,7 @@ do_test 1.4 {
# such that the payload begins in allocated space but overflows the buffer.
#
db close
hexio_write test.db [expr {3*512-15}] 0513ff7f01
hexio_write test.db [expr {$idxroot*512-15}] 0513ff7f01
sqlite3 db test.db
do_test 2.1 {
+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
+2 -2
View File
@@ -191,8 +191,8 @@ do_insert_tests e_insert-1.3 {
3b "SELECT * FROM a2 WHERE oid=last_insert_rowid()" {2 x y}
}
# EVIDENCE-OF: R-44710-64652 If a column-list is specified, then the
# number of values in each term of the VALUS list must match the number
# EVIDENCE-OF: R-09234-17933 If a column-list is specified, then the
# number of values in each term of the VALUE list must match the number
# of specified columns.
#
do_insert_tests e_insert-1.4 -error {
+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
+7
View File
@@ -426,4 +426,11 @@ do_execsql_test 8.3 {
{0 3 2 0 3 2 1 4 3} {1 3 2 1 3 2 1 4 3} {2 3 2 2 3 2 2 4 3}
}
do_execsql_test 9.1 {
CREATE VIRTUAL TABLE ft2 USING fts4;
INSERT INTO ft2 VALUES('a b c d e');
INSERT INTO ft2 VALUES('f a b c d');
SELECT snippet(ft2, '[', ']', '', -1, 1) FROM ft2 WHERE ft2 MATCH 'c';
} {{[c]} {[c]}}
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
+8 -3
View File
@@ -16,6 +16,11 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !vtab {
finish_test
return
}
load_static_extension db wholenumber;
do_test index6-1.1 {
# Able to parse and manage partial indices
@@ -144,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;
+47
View File
@@ -13,6 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix indexedby
# Create a schema with some indexes.
#
@@ -274,4 +275,50 @@ do_test indexedby-10.3 {
}
} {1}
#-------------------------------------------------------------------------
# Ensure that the rowid at the end of each index entry may be used
# for equality constraints in the same way as other indexed fields.
#
do_execsql_test 11.1 {
CREATE TABLE x1(a, b TEXT);
CREATE INDEX x1i ON x1(a, b);
INSERT INTO x1 VALUES(1, 1);
INSERT INTO x1 VALUES(1, 1);
INSERT INTO x1 VALUES(1, 1);
INSERT INTO x1 VALUES(1, 1);
}
do_execsql_test 11.2 {
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid=3;
} {1 1 3}
do_execsql_test 11.3 {
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3';
} {1 1 3}
do_execsql_test 11.4 {
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {1 1 3}
do_eqp_test 11.5 {
SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
} {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}}
do_execsql_test 11.6 {
CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
CREATE INDEX x2i ON x2(a, b);
INSERT INTO x2 VALUES(1, 1, 1);
INSERT INTO x2 VALUES(2, 1, 1);
INSERT INTO x2 VALUES(3, 1, 1);
INSERT INTO x2 VALUES(4, 1, 1);
}
do_execsql_test 11.7 {
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3;
} {1 1 3}
do_execsql_test 11.8 {
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3';
} {1 1 3}
do_execsql_test 11.9 {
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {1 1 3}
do_eqp_test 11.10 {
SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
} {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}}
finish_test
+2
View File
@@ -205,6 +205,7 @@ do_test malloc5-4.1 {
execsql "INSERT INTO abc VALUES($i, $i, '[string repeat X 100]');"
}
execsql {COMMIT;}
db cache flush
sqlite3_release_memory
sqlite3_memory_highwater 1
execsql {SELECT * FROM abc}
@@ -213,6 +214,7 @@ do_test malloc5-4.1 {
expr $nMaxBytes > 1000000
} {1}
do_test malloc5-4.2 {
db cache flush
sqlite3_release_memory
sqlite3_soft_heap_limit 100000
sqlite3_memory_highwater 1
+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}
+27 -1
View File
@@ -93,6 +93,14 @@ set FAULTSIM(cantopen-persistent) [list \
-injectuninstall cantopen_injectuninstall \
]
set FAULTSIM(interrupt) [list \
-injectinstall interrupt_injectinstall \
-injectstart interrupt_injectstart \
-injectstop interrupt_injectstop \
-injecterrlist {{1 interrupted} {1 interrupt}} \
-injectuninstall interrupt_injectuninstall \
]
#--------------------------------------------------------------------------
@@ -113,7 +121,9 @@ set FAULTSIM(cantopen-persistent) [list \
proc do_faultsim_test {name args} {
global FAULTSIM
set DEFAULT(-faults) [array names FAULTSIM]
foreach n [array names FAULTSIM] {
if {$n != "interrupt"} {lappend DEFAULT(-faults) $n}
}
set DEFAULT(-prep) ""
set DEFAULT(-body) ""
set DEFAULT(-test) ""
@@ -255,6 +265,22 @@ proc cantopen_injectstop {} {
shmfault cantopen
}
# The following procs are used as [do_one_faultsim_test] callbacks
# when injecting SQLITE_INTERRUPT error faults into test cases.
#
proc interrupt_injectinstall {} {
}
proc interrupt_injectuninstall {} {
}
proc interrupt_injectstart {iFail} {
set ::sqlite_interrupt_count $iFail
}
proc interrupt_injectstop {} {
set res [expr $::sqlite_interrupt_count<=0]
set ::sqlite_interrupt_count 0
set res
}
# This command is not called directly. It is used by the
# [faultsim_test_result] command created by [do_faultsim_test] and used
# by -test scripts.
+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
+79
View File
@@ -22,6 +22,7 @@ source $testdir/tester.tcl
# pragma2-1.*: Test freelist_count pragma on the main database.
# pragma2-2.*: Test freelist_count pragma on an attached database.
# pragma2-3.*: Test trying to write to the freelist_count is a no-op.
# pragma2-4.*: Tests for PRAGMA cache_spill
#
ifcapable !pragma||!schema_pragmas {
@@ -116,4 +117,82 @@ ifcapable attach {
} {9 9}
}
# Default setting of PRAGMA cache_spill is always ON
#
db close
delete_file test.db test.db-journal
delete_file test2.db test2.db-journal
sqlite3 db test.db
do_execsql_test pragma2-4.1 {
PRAGMA cache_spill;
PRAGMA main.cache_spill;
PRAGMA temp.cache_spill;
} {1 1 1}
do_execsql_test pragma2-4.2 {
PRAGMA cache_spill=OFF;
PRAGMA cache_spill;
PRAGMA main.cache_spill;
PRAGMA temp.cache_spill;
} {0 0 0}
do_execsql_test pragma2-4.3 {
PRAGMA page_size=1024;
PRAGMA cache_size=50;
BEGIN;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c, d);
INSERT INTO t1 VALUES(1, randomblob(400), 1, randomblob(400));
INSERT INTO t1 SELECT a+1, randomblob(400), a+1, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+2, randomblob(400), a+2, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+4, randomblob(400), a+4, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+8, randomblob(400), a+8, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+16, randomblob(400), a+16, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+32, randomblob(400), a+32, randomblob(400) FROM t1;
INSERT INTO t1 SELECT a+64, randomblob(400), a+64, randomblob(400) FROM t1;
COMMIT;
ATTACH 'test2.db' AS aux1;
CREATE TABLE aux1.t2(a INTEGER PRIMARY KEY, b, c, d);
INSERT INTO t2 SELECT * FROM t1;
DETACH aux1;
PRAGMA cache_spill=ON;
} {}
sqlite3_release_memory
do_test pragma2-4.4 {
db eval {
BEGIN;
UPDATE t1 SET c=c+1;
PRAGMA lock_status;
}
} {main exclusive temp unknown} ;# EXCLUSIVE lock due to cache spill
do_test pragma2-4.5 {
db eval {
COMMIT;
PRAGMA cache_spill=OFF;
BEGIN;
UPDATE t1 SET c=c-1;
PRAGMA lock_status;
}
} {main reserved temp unknown} ;# No cache spill, so no exclusive lock
# Verify that newly attached databases inherit the cache_spill=OFF
# setting.
#
do_execsql_test pragma2-4.6 {
COMMIT;
ATTACH 'test2.db' AS aux1;
PRAGMA aux1.cache_size=50;
BEGIN;
UPDATE t2 SET c=c+1;
PRAGMA lock_status;
} {main unlocked temp unknown aux1 reserved}
do_execsql_test pragma2-4.7 {
COMMIT;
}
sqlite3_release_memory
do_execsql_test pragma2-4.8 {
PRAGMA cache_spill=ON; -- Applies to all databases
BEGIN;
UPDATE t2 SET c=c-1;
PRAGMA lock_status;
} {main unlocked temp unknown aux1 exclusive}
finish_test
+2
View File
@@ -164,10 +164,12 @@ do_test progress-1.7 {
}
set ::res [list]
explain {SELECT a, b, c FROM abc}
db eval {SELECT a, b, c FROM abc} {
lappend ::res $a $b $c
db progress 5 "expr 1"
catch {db eval {SELECT a, b, c FROM abc} { }} msg
db progress 5 "expr 0"
lappend ::res $msg
}
+171 -2
View File
@@ -13,10 +13,18 @@
# figures out what identifiers in the SQL statement refer to) that
# were fixed by ticket [2500cdb9be]
#
# See also tickets [1c69be2daf] and [f617ea3125] from 2013-08-14.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# "ORDER BY y" binds to the output result-set column named "y"
# if available. If no output column is named "y", then try to
# bind against an input column named "y".
#
# This is classical SQL92 behavior.
#
do_test resolver01-1.1 {
catchsql {
CREATE TABLE t1(x, y); INSERT INTO t1 VALUES(11,22);
@@ -25,15 +33,176 @@ do_test resolver01-1.1 {
}
} {0 1}
do_test resolver01-1.2 {
catchsql {
SELECT 1 AS yy FROM t1, t2 ORDER BY y;
}
} {1 {ambiguous column name: y}}
do_test resolver01-1.3 {
catchsql {
CREATE TABLE t3(x,y); INSERT INTO t3 VALUES(11,44),(33,22);
SELECT x AS y FROM t3 ORDER BY y;
}
} {0 {11 33}}
do_test resolver01-1.4 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY y;
}
} {0 {33 11}}
# SQLite allows the WHERE clause to reference output columns if there is
# no other way to resolve the name.
#
do_test resolver01-1.5 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY yy;
}
} {0 {11 33}}
do_test resolver01-1.6 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY 1;
}
} {0 {11 33}}
# The "ORDER BY y COLLATE nocase" form works the same as "ORDER BY y".
# The "y" binds more tightly to output columns than to input columns.
#
# This is for compatibility with SQL92 and with historical SQLite behavior.
# Note that PostgreSQL considers "y COLLATE nocase" to be an expression
# and thus PostgreSQL treats this case as if it where the 3.x case below.
#
do_test resolver01-2.1 {
catchsql {
SELECT 2 AS y FROM t1, t2 ORDER BY y COLLATE nocase;
}
} {0 2}
do_test resolver01-1.3 {
do_test resolver01-2.2 {
catchsql {
SELECT 2 AS yy FROM t1, t2 ORDER BY y COLLATE nocase;
}
} {1 {ambiguous column name: y}}
do_test resolver01-2.3 {
catchsql {
SELECT x AS y FROM t3 ORDER BY y COLLATE nocase;
}
} {0 {11 33}}
do_test resolver01-2.4 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY y COLLATE nocase;
}
} {0 {33 11}}
do_test resolver01-2.5 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY yy COLLATE nocase;
}
} {0 {11 33}}
do_test resolver01-2.6 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY 1 COLLATE nocase;
}
} {0 {11 33}}
# But if the form is "ORDER BY expr" then bind more tightly to the
# the input column names and only use the output column names if no
# input column name matches.
#
# This is SQL99 behavior, as implemented by PostgreSQL and MS-SQL.
# Note that Oracle works differently.
#
do_test resolver01-3.1 {
catchsql {
SELECT 3 AS y FROM t1, t2 ORDER BY +y;
}
} {0 3}
} {1 {ambiguous column name: y}}
do_test resolver01-3.2 {
catchsql {
SELECT 2 AS yy FROM t1, t2 ORDER BY +y;
}
} {1 {ambiguous column name: y}}
do_test resolver01-3.3 {
catchsql {
SELECT x AS y FROM t3 ORDER BY +y;
}
} {0 {33 11}}
do_test resolver01-3.4 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY +y;
}
} {0 {33 11}}
do_test resolver01-3.5 {
catchsql {
SELECT x AS yy FROM t3 ORDER BY +yy
}
} {0 {11 33}}
# This is the test case given in ticket [f617ea3125e9] (with table name
# changed from "t1" to "t4". The behavior of (1) and (3) match with
# PostgreSQL, but we intentionally break with PostgreSQL to provide
# SQL92 behavior for case (2).
#
do_execsql_test resolver01-4.1 {
CREATE TABLE t4(m CHAR(2));
INSERT INTO t4 VALUES('az');
INSERT INTO t4 VALUES('by');
INSERT INTO t4 VALUES('cx');
SELECT '1', substr(m,2) AS m FROM t4 ORDER BY m;
SELECT '2', substr(m,2) AS m FROM t4 ORDER BY m COLLATE binary;
SELECT '3', substr(m,2) AS m FROM t4 ORDER BY lower(m);
} {1 x 1 y 1 z 2 x 2 y 2 z 3 z 3 y 3 x}
##########################################################################
# Test cases for ticket [1c69be2dafc28]: Make sure the GROUP BY binds
# more tightly to the input tables in all cases.
#
# This first case case has been wrong in SQLite for time out of mind.
# For SQLite version 3.7.17 the answer was two rows, which is wrong.
#
do_execsql_test resolver01-5.1 {
CREATE TABLE t5(m CHAR(2));
INSERT INTO t5 VALUES('ax');
INSERT INTO t5 VALUES('bx');
INSERT INTO t5 VALUES('cy');
SELECT count(*), substr(m,2,1) AS m FROM t5 GROUP BY m ORDER BY 1, 2;
} {1 x 1 x 1 y}
# This case is unambiguous and has always been correct.
#
do_execsql_test resolver01-5.2 {
SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY m ORDER BY 1, 2;
} {1 x 1 x 1 y}
# This case is not allowed in standard SQL, but SQLite allows and does
# the sensible thing.
#
do_execsql_test resolver01-5.3 {
SELECT count(*), substr(m,2,1) AS mx FROM t5 GROUP BY mx ORDER BY 1, 2;
} {1 y 2 x}
do_execsql_test resolver01-5.4 {
SELECT count(*), substr(m,2,1) AS mx FROM t5
GROUP BY substr(m,2,1) ORDER BY 1, 2;
} {1 y 2 x}
# These test case weere provided in the 2013-08-14 email from Rob Golsteijn
# that originally reported the problem of ticket [1c69be2dafc28].
#
do_execsql_test resolver01-6.1 {
CREATE TABLE t61(name);
SELECT min(name) FROM t61 GROUP BY lower(name);
} {}
do_execsql_test resolver01-6.2 {
SELECT min(name) AS name FROM t61 GROUP BY lower(name);
} {}
do_execsql_test resolver01-6.3 {
CREATE TABLE t63(name);
INSERT INTO t63 VALUES (NULL);
INSERT INTO t63 VALUES ('abc');
SELECT count(),
NULLIF(name,'abc') AS name
FROM t63
GROUP BY lower(name);
} {1 {} 1 {}}
finish_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
}
+79
View File
@@ -0,0 +1,79 @@
# 2013 August 29
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix tkt-9f2eb3abac
do_execsql_test 1.1 {
CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e));
SELECT * FROM t1 WHERE a=? AND b=? AND c=? AND d=? AND e=?;
} {}
do_execsql_test 1.2 {
CREATE TABLE "a" (
"b" integer NOT NULL,
"c" integer NOT NULL,
PRIMARY KEY ("b", "c")
);
CREATE TABLE "d" (
"e" integer NOT NULL,
"g" integer NOT NULL,
"f" integer NOT NULL,
"h" integer NOT NULL,
"i" character(10) NOT NULL,
"j" int,
PRIMARY KEY ("e", "g", "f", "h")
);
CREATE TABLE "d_to_a" (
"f_e" integer NOT NULL,
"f_g" integer NOT NULL,
"f_f" integer NOT NULL,
"f_h" integer NOT NULL,
"t_b" integer NOT NULL,
"t_c" integer NOT NULL,
"r" character NOT NULL,
"s" integer,
PRIMARY KEY ("f_e", "f_g", "f_f", "f_h", "t_b", "t_c")
);
INSERT INTO d (g, e, h, f, j, i) VALUES ( 1, 1, 1, 1, 1, 1 );
INSERT INTO a (b, c) VALUES ( 1, 1 );
INSERT INTO d_to_a VALUES (1, 1, 1, 1, 1, 1, 1, 1);
DELETE FROM d_to_a
WHERE f_g = 1 AND f_e = 1 AND f_h = 1 AND f_f = 1 AND t_b = 1 AND t_c = 1;
SELECT * FROM d_to_a;
} {}
faultsim_delete_and_reopen
do_execsql_test 2.0 { CREATE TABLE t1(a,b,c,d,e, PRIMARY KEY(a,b,c,d,e)) }
do_execsql_test 2.1 { CREATE TABLE t2(x) }
faultsim_save_and_close
do_faultsim_test 3 -faults oom* -prep {
faultsim_restore_and_reopen
execsql { SELECT 1 FROM sqlite_master }
} -body {
execsql { SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=? AND e=? }
} -test {
faultsim_test_result {0 {}}
}
finish_test
+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
+1 -4
View File
@@ -208,15 +208,12 @@ do_test tkt2822-5.4 {
# In "ORDER BY +b" the term is now an expression rather than
# a label. It therefore matches by rule (3) instead of rule (2).
#
# 2013-04-13: This is busted. Changed to conform to PostgreSQL and
# MySQL and Oracle behavior.
#
do_test tkt2822-5.5 {
execsql {
SELECT a AS b FROM t3 ORDER BY +b;
}
} {1 9}
} {9 1}
# Tests for rule 2 in compound queries
#
+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
+2
View File
@@ -701,6 +701,7 @@ do_test where2-11.4 {
# Verify that the OR clause is used in an outer loop even when
# the OR clause scores slightly better on an inner loop.
if {[permutation] != "no_optimization"} {
do_execsql_test where2-12.1 {
CREATE TABLE t12(x INTEGER PRIMARY KEY, y);
CREATE INDEX t12y ON t12(y);
@@ -709,6 +710,7 @@ do_execsql_test where2-12.1 {
FROM t12 AS a JOIN t12 AS b ON a.y=b.x
WHERE (b.x=$abc OR b.y=$abc);
} {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/}
}
finish_test
+6
View File
@@ -246,6 +246,12 @@ do_execsql_test where3-3.1 {
0 0 1 {SCAN TABLE t302}
0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)}
}
do_execsql_test where3-3.2 {
SELECT * FROM t301 WHERE c=3 AND a IS NULL;
} {}
do_execsql_test where3-3.3 {
SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL;
} {1 2 3}
if 0 { # Query planner no longer does this
# Verify that when there are multiple tables in a join which must be
+32 -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 {
@@ -951,4 +956,28 @@ do_test where9-9.1 {
}
} {1 2 3 4 8 9}
# Fix for ticket [bc878246eafe0f52c519e29049b2fe4a99491b27]
# Incorrect result when OR is used in a join to the right of a LEFT JOIN
#
do_test where9-10.1 {
db eval {
CREATE TABLE t101 (id INTEGER PRIMARY KEY);
INSERT INTO t101 VALUES (1);
SELECT * FROM t101 AS t0
LEFT JOIN t101 AS t1 ON t1.id BETWEEN 10 AND 20
JOIN t101 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
}
} {1 {} 1}
do_test where9-10.2 {
db eval {
CREATE TABLE t102 (id TEXT UNIQUE NOT NULL);
INSERT INTO t102 VALUES ('1');
SELECT * FROM t102 AS t0
LEFT JOIN t102 AS t1 ON t1.id GLOB 'abc%'
JOIN t102 AS t2 ON (t2.id = t0.id OR (t2.id<>555 AND t2.id=t1.id));
}
} {1 {} 1}
finish_test
+6
View File
@@ -68,6 +68,12 @@ do_test whereA-1.7 {
SELECT * FROM t1;
}
} {3 4.53 {} 2 hello world 1 2 3}
do_execsql_test whereA-1.8 {
SELECT * FROM t1 WHERE b=2 AND a IS NULL;
} {}
do_execsql_test whereA-1.9 {
SELECT * FROM t1 WHERE b=2 AND a IS NOT NULL;
} {1 2 3}
do_test whereA-2.1 {
db eval {
+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
+14 -1
View File
@@ -23,6 +23,16 @@ set -u
TMPSPACE=./mkpkg_tmp_dir
VERSION=`cat $TOP/VERSION`
# Set global variable $ARTIFACT to the "3xxyyzz" string incorporated
# into artifact filenames. And $VERSION2 to the "3.x.y[.z]" form.
xx=`echo $VERSION|sed 's/3\.\([0-9]*\)\..*/\1/'`
yy=`echo $VERSION|sed 's/3\.[^.]*\.\([0-9]*\).*/\1/'`
zz=0
set +e
zz=`echo $VERSION|sed 's/3\.[^.]*\.[^.]*\.\([0-9]*\).*/\1/'|grep -v '\.'`
set -e
ARTIFACT=`printf "3%.2d%.2d%.2d" $xx $yy $zz`
rm -rf $TMPSPACE
cp -R $TOP/autoconf $TMPSPACE
@@ -66,5 +76,8 @@ rm -rf autom4te.cache
cd ../
./configure && make dist
mv sqlite-$VERSION.tar.gz ../sqlite-amalgamation-$VERSION.tar.gz
tar -xzf sqlite-$VERSION.tar.gz
mv sqlite-$VERSION sqlite-autoconf-$ARTIFACT
tar -czf sqlite-autoconf-$ARTIFACT.tar.gz sqlite-autoconf-$ARTIFACT
mv sqlite-autoconf-$ARTIFACT.tar.gz ..
+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"