Compare commits

..

126 Commits

Author SHA1 Message Date
mistachkin 7f61e13f72 Fix several harmless compiler warnings.
FossilOrigin-Name: 360c0fd1cf9db5f1e4f670a4b95971daaeaa5879
2014-05-09 00:36:06 +00:00
mistachkin 5c8b293c75 Fix typos in logging code.
FossilOrigin-Name: dc7f84dfcc8415fad4af041fd30c20b3fd91be45
2014-05-08 22:15:13 +00:00
mistachkin df5e9e977b Fix a memory leak of the temporary read buffer.
FossilOrigin-Name: 37e60d211f70d12eda6d8b63da5e5e307e9d1748
2014-05-08 22:08:22 +00:00
mistachkin 04de790b09 Update comments and only include the thread routine when required.
FossilOrigin-Name: a60c545f255f7da53e0ebcde8743532b54bafdb6
2014-05-08 22:05:30 +00:00
mistachkin 83dca19e9f Experimental changes to pre-cache a database file prior to it being fully opened.
FossilOrigin-Name: 38cbcedbb6e57dc3c2d452a0eb573cabc7df0c75
2014-05-08 22:01:26 +00:00
mistachkin df24cf81a6 Fix static variable declaration issue on Windows.
FossilOrigin-Name: a41d29691307067523c8637b486941c5f7c33775
2014-05-08 22:01:08 +00:00
dan 5a7dbc70ea Add a little extra variety to the tests in sort4.test.
FossilOrigin-Name: 7de6aee6a5cb5c7f89dced89f2ebf38f8be7a4fa
2014-05-06 16:21:30 +00:00
dan dfea45330e Re-implement the core of the multi-threaded sorter tests in sort4.test using C. Run each test in sort4.test ten times, or repeat all tests for 300 seconds as part of the "multithread" permutation test.
FossilOrigin-Name: 208b2b04d4d282bec4424ea7160a123ba549d118
2014-05-06 15:38:07 +00:00
dan 449cb9a5af Add test file sort4.test, containing brute force tests for the multi-theaded sorter.
FossilOrigin-Name: 9cc364c42cc64ab7b55b5c55e303fb63a456cf00
2014-05-05 20:03:50 +00:00
dan 0d3a4085e5 Fix a race condition in the sorter code.
FossilOrigin-Name: 2d2edfe58db101d42a96772b856e6e55b401aab6
2014-05-05 15:58:40 +00:00
dan d94d4ee7bd Add tests so that the "coverage-sorter" test permutation covers all branches in vdbesort.c. Fix a few minor problems in the same file.
FossilOrigin-Name: bde28b702dabd02269e333535cc41481351c5efc
2014-05-05 09:08:54 +00:00
dan f7f425d600 Add an extra fault-injection test to sortfault.test. Remove an unreachable branch from vdbesort.c.
FossilOrigin-Name: a33a366ba8a0da81ddd895d552a348441ef8529a
2014-05-03 20:43:13 +00:00
dan e18e90ebaf Fix a race condition in the sorter.
FossilOrigin-Name: 32ccf3ae18531682dfd039fa8df6ad9a907ac455
2014-05-03 19:33:00 +00:00
dan 0d51def29e Fix a problem in the sorter causing it to return spurious SQLITE_NOMEM errors when configured to use memsys3 or memsys5.
FossilOrigin-Name: 3a66c4e1bf311d38668dfcdcd77867feff6db7bd
2014-05-03 14:28:14 +00:00
drh 2fc7bc08bd Get SQLITE_MUTEX_STATIC_APP1 and _APP2 working for the debugMutex
implementation.

FossilOrigin-Name: f49ba1c926c63ee1c4609930138389fca182c845
2014-05-03 13:53:37 +00:00
drh 7bd3c89114 Add two new static mutexes, SQLITE_MUTEX_STATIC_APP1 and _APP2, for use by
the application program.  First intended use is in test programs for the
memory allocation logic where one does not want to allocating a _FAST
or _RECURSIVE mutex since that would involve using the memory allocation
system under test.

FossilOrigin-Name: 13686035dd1cf67ad9c6d282ab13c3259e7273d1
2014-05-03 12:00:01 +00:00
drh a09c8855b7 Add the SQLITE_DEFAULT_WORKER_THREADS compile-time option.
Fix a NULL-pointer dereference that can occur following OOM.

FossilOrigin-Name: e0dea89b3e9f295f80210fcca007681bf1b08692
2014-05-03 11:22:09 +00:00
mistachkin e500747cfe Fix typo in Windows makefile. Make sure the WaitForSingleObjectEx system call is always available.
FossilOrigin-Name: d7ed529fa2aa5cb13edaabca2acaad06dffef569
2014-05-02 19:12:37 +00:00
drh 84de690b4f Do not run the vdbeRecordCompareDebug() assert if pKeyInfo->db is NULL since
in that case there would be no way to check for a memory allocation failure.

FossilOrigin-Name: 63ed2d6acb82be8a74dbf6a61388be6da6113985
2014-05-02 18:46:52 +00:00
dan 2ae56f50ce Merge orderby-planning with this branch.
FossilOrigin-Name: d9549de31741239ece060e448b592ce8fc5b8042
2014-05-02 18:05:38 +00:00
drh 79211e194d Simplify assert() statements used to verify correct operation of
record comparison routines.

FossilOrigin-Name: 3300d62dcbe74842cf86ca436959fe4e77a89f84
2014-05-02 17:33:16 +00:00
dan a7bf23c6b5 Fix some broken asserts in btree.c and vdbeaux.c that may fail following an OOM error.
FossilOrigin-Name: e15f47064bef431c0afd8bf93eb4e160c23ad562
2014-05-02 17:12:41 +00:00
drh c7f6c148d9 Failure to extend a temp file for use with mmap() in vdbesort.c is benign.
FossilOrigin-Name: d4d396387d373bd1e82eda2c7c2e7ca35ec099c4
2014-05-02 16:22:55 +00:00
dan 012e133772 Remove a faulty assert() from vdbesort.c.
FossilOrigin-Name: d95d68aa1d14b750888d50068380cc107f9070df
2014-05-02 16:03:57 +00:00
drh 7a0fd192cc Fix a faulty assert() statement.
FossilOrigin-Name: 9196ce407379ca3b151b601b98848771e5cb4e8f
2014-05-02 15:25:24 +00:00
drh fb0d6e56d6 Merge latest trunk enhancements and fixes into the orderby-planning branch.
FossilOrigin-Name: 84862d3a095629d20c8e7b8a16f4dc26cd41ab6d
2014-05-02 13:09:06 +00:00
drh e724d3d26a Add a comment explaining why WhereLoop cost adjustments are omitted for
skip-scan loops.

FossilOrigin-Name: 3bc43594aaeee9225c0590677fcce480bedcb37b
2014-05-02 00:09:40 +00:00
dan 3852413246 Fix an obscure problem to do with temp register allocation that could occur if more than one simple SELECT within a compound SELECT uses a partial sort.
FossilOrigin-Name: 427409ae106cdab7892a6b50fe30c5f52de5addc
2014-05-01 20:26:48 +00:00
drh c5f246eb37 Add #ifdefs for test coverage. Add a testcase().
FossilOrigin-Name: be2702ce35c713b33c9b7689643b45fb0de6af2a
2014-05-01 20:24:21 +00:00
dan e03d76254c Update a test case in wal2.test that explicitly corrupts a checksum in the wal file to account for the fact that the first byte of said checksum may initially be 0xFF.
FossilOrigin-Name: 2b935bdea1452505f36dc8c7aad49e6c42f4eceb
2014-05-01 10:19:16 +00:00
dan 5da73e1a09 Fix a problem in calculating the costs of "OR" scans.
FossilOrigin-Name: 9bbca48b42e4fe16f2188e18dc736da30a96435c
2014-04-30 18:11:55 +00:00
dan 4243e27f22 Modify the way the costs of various query plans are estimated. If the user supplies a likelihood() value (or equivalent) on an indexed WHERE constraint, use it to estimate the number of index rows visited.
FossilOrigin-Name: 90e36676476e8db00658772e6c938242f766d306
2014-04-30 15:22:25 +00:00
dan 8164722c58 Add text to the header comment of whereLoopAddBtree() describing how the costs of various b-tree loops are estimated.
FossilOrigin-Name: 05e6e16cb28c9ffb4596bd2ef81f687c5403ecbb
2014-04-30 15:00:16 +00:00
dan 75525cbe24 Update a couple of test cases to account for the fact that this branch prefers an index scan and partial sort over a full-table scan and full external sort.
FossilOrigin-Name: 9b975bf33cd8fc28c64183a9642bf9fb436a4746
2014-04-30 14:53:21 +00:00
dan 4a6b8a05cd Fix a couple of out-of-date comments in where.c.
FossilOrigin-Name: eefeda32d54efbbdf7d20b719299eda48b891fae
2014-04-30 14:47:01 +00:00
drh 253666e520 Improved rendering of LogEst values corresponding to real values near 0.0
in the tool/logest.c utility program.

FossilOrigin-Name: 32910c8c595858245bb7ecfe3aa0f90eeae641af
2014-04-30 14:22:38 +00:00
drh 224155dd1c Fix long-standing typos in comments.
FossilOrigin-Name: b9f91317c34d07769a95dc2f905a6ccabceb64a3
2014-04-30 13:19:09 +00:00
dan 264d2b97a9 Test that the default values used when sqlite_stat1 data is not available are calculated correctly. Fixes for the same.
FossilOrigin-Name: e2d42f909de85a0586389f2dc0e654f7af2e351a
2014-04-29 19:01:57 +00:00
dan e4618fb30d Merge trunk changes into this branch.
FossilOrigin-Name: d74299f037f3a6a4b3bce8b4d1c76c407c1f3b3e
2014-04-29 16:46:24 +00:00
dan 09e1df6c00 Ignore likelihood() values on indexed IPK lookups.
FossilOrigin-Name: 5bb7757a7b32a74482d3e93e9c9eea02273fe981
2014-04-29 16:10:22 +00:00
dan 67a03cfd6e Fix a test case so that it updates sqlite_stat1 consistently.
FossilOrigin-Name: 2dc5a0b55567f13f0528ed17242e680cde2f2a29
2014-04-29 12:01:35 +00:00
dan 7de2a1faf6 Do not reduce the number of rows scanned at all for "IS NOT NULL" constraints. Fix a bug in calculating the number of rows visited by scans of partial indicies.
FossilOrigin-Name: a8ae93f0cffa116df0ba34d46a53f49d42dace41
2014-04-28 20:11:20 +00:00
dan 42685f211e The trunk assumes that an open range constraint on an indexed term (col>?) term matches 1/4 of the indexed rows, and that a closed constraint (col BETWEEN ? AND ?) matches 1/64. Change this branch to do the same.
FossilOrigin-Name: 4047ac75e2a8f0b330255501c42e4f04e5ab500d
2014-04-28 19:34:06 +00:00
drh 65e6b0dd12 Add the sqlite3_rtree_query_callback() API to the RTree virtual table.
(Cherrypick from the sessions branch.)

FossilOrigin-Name: af2cbe64adab5f9e3b0f3da00d06428088589d7f
2014-04-28 17:56:19 +00:00
dan 6b6828625b Update unordered.test to take into account for the fact that SQLite now prefers a full-table scan over a non-covering index scan that visits a large percentage of the table rows.
FossilOrigin-Name: 20f468dfbcb247e51446fad411a6e6cc0d130411
2014-04-28 15:11:25 +00:00
dan 9881d60d17 Add an extra column to a table in analyze9.test to give the planner a little more reason to select an index.
FossilOrigin-Name: 1b95544f84bf83c28cc15f6d0690fdf8a6bb3941
2014-04-28 12:08:23 +00:00
dan b51926e67c Update test script analyze3.test to account for the fact that SQLite now prefers a full-table scan over a non-covering index scan that visits a large percentage of the table rows.
FossilOrigin-Name: 35f46a55d866b9a87c1321aab8e0cfe86ccadb93
2014-04-28 10:00:59 +00:00
dan e3bfbb7284 Modify internal function whereLoopAdjustCost() so that it does not prefer a skip-scan over a regular index scan even if the regular scan uses a subset of the WHERE terms used by the skip-scan.
FossilOrigin-Name: 88a5758dcce891eb7be15432ebdc9f80071d413b
2014-04-28 09:35:31 +00:00
dan 440e6ff3b0 Fix an error in estimating of the number of rows visited by a range scan.
FossilOrigin-Name: d491de62fce69d93e89f65f7713972f7c2c451f7
2014-04-28 08:49:54 +00:00
dan 2dd3cdcfab Fix an sqlite3_stmt_status() problem caused by recent changs on this branch.
FossilOrigin-Name: dee204092421a239f9f60ab83c3a5b3e24d1baea
2014-04-26 20:21:14 +00:00
drh 1f8bb4b0a8 Update requirements marks to fix typos in the requirements text.
No changes to code.

FossilOrigin-Name: f5a263658187250044afc1a74000e6f6962733ca
2014-04-26 19:23:14 +00:00
drh 453e0261df Allow the xfer optimization to proceed if the DEFAULT on the very first
column of the two tables is different.  This is a refinement of the
fix for ticket [f67b41381a].

FossilOrigin-Name: 349f483499dd685a8da94923b6bd810a52e5e236
2014-04-26 17:52:08 +00:00
dan 9940e2aa45 Avoid transfering records between tables unless the default values for all columns are the same. Fix for [f67b41381a].
FossilOrigin-Name: f8c4c495e6de1f124d205383d4bafa46accbff5c
2014-04-26 14:07:57 +00:00
dan 8ad1d8ba38 If the user provides likelihood() data for a WHERE clause term used as part of an index key, have the planner use it when calculating the expected number of rows visited by the loop.
FossilOrigin-Name: c51efaa5d29ee0a91b9e6a83a8dd82530670811a
2014-04-25 20:22:45 +00:00
drh b79c718f1a Add test cases to ensure correct operation of joins with a virtual table
that include DISTINCT and ORDER BY clauses.  Verification for ticket
[388d01d4bb8f9].

FossilOrigin-Name: 5ada136f43ce744ae8c349eff39838eb44611b6e
2014-04-25 17:37:16 +00:00
dan cfc9df76e1 Store values loaded from the stat1 table as logarithmic values in memory.
FossilOrigin-Name: 1bd74c49ddab6f53bb6eaa57907eff44c2580dd6
2014-04-25 15:01:01 +00:00
drh 9dfaf621d1 Make sure ORDER BY clauses on joins that involve virtual tables and that
have a DISTINCT clause work correctly.  This is a candidate fix for
ticket [388d01d4bb8f9].  Test cases for that ticket will be checked in
separately.

FossilOrigin-Name: 171138122690faafde0dcab0201b90bdf02d3637
2014-04-25 14:42:17 +00:00
drh a01c7c70fd When VDBE_PROFILE is enabled, ignore negative opcode times, which sometimes
occur, perhaps due to context swaps.

FossilOrigin-Name: 4e88042f9d3e678914da96c0eb276f3d8fca5a94
2014-04-25 12:35:31 +00:00
dan aa9933c115 Changes to the way the planner calculates the costs of various table and index scans. Some test cases still failing.
FossilOrigin-Name: c5a6ec0a880652dc8f4593d9f7acd58ddc3dc5f3
2014-04-24 20:04:49 +00:00
drh f690c14280 Improved header comment on the vdbesort.c module. No changes to code.
FossilOrigin-Name: bf09ce24d054bc68c226064f5f28d97e0e648a13
2014-04-24 16:25:25 +00:00
drh 0ff435a782 Reopen the orderby-planning branch and merge in the latest trunk enhancements
and fixes.

FossilOrigin-Name: 6077ddcd93318e24b9756adaaf293ba9fb3cedf7
2014-04-24 15:06:25 +00:00
drh 3de4df27dd Improvements to comments. Store some extra information in SqliteThread that
is useful for debugging.

FossilOrigin-Name: 9fb5e212089d85cdd3b4787dd69c72e6d84560b6
2014-04-24 12:28:28 +00:00
drh 9e0ed8d4ec Merge all recent trunk changes into the threads branch.
FossilOrigin-Name: e2c9f71a451e44040624b9f255b4510743513019
2014-04-23 12:57:55 +00:00
drh 46a06bbe47 Add to speedtest1.c the --threads option for setting the
SQLITE_CONFIG_WORKER_THREADS configuration.

FossilOrigin-Name: 5fce40c44aacf883df2e8e9472c399a6e92197b3
2014-04-18 13:57:39 +00:00
drh 958d261bb8 Fix harmless compiler warnings.
FossilOrigin-Name: f8f72ecb9052a4cace1db75879fb8b5131ea4f50
2014-04-18 13:40:07 +00:00
drh e9af1894e3 Merge recent trunk changes into the threads branch.
FossilOrigin-Name: 8729aa3e3ed1da2e15408ef8705cbe185cd2a5ac
2014-04-18 12:38:54 +00:00
dan a9f43d735b Fix build problems in vdbesort.c. Add further comments and changes to make things easier to understand.
FossilOrigin-Name: 12b190db1d20c34390c768614b40ff58a9d3b74c
2014-04-17 08:57:17 +00:00
dan 31a0bfde9b Clarify the purpose of the nField argument passed to sqlite3VdbeSorterInit().
FossilOrigin-Name: c0c8cff17b7311bbc4fd081313a5552f927c3833
2014-04-16 19:04:23 +00:00
dan db30fc4ff2 Change the name of vdbeIncrInit2 to vdbePmaReaderIncrInit. Add a header comment to the same function.
FossilOrigin-Name: 6622d87675c1d7992b1e6d52ae7da1007a1568a4
2014-04-16 17:41:22 +00:00
dan 7f0a24b7bf Rework the way trees of MergeEngine objects are built in vdbesort.c to make it easier to follow. Fix memory leaks that could follow an OOM or IO error. Add various comments to explain functions in vdbesort.c.
FossilOrigin-Name: 69026ec7dc3bd3e33bbe17c221a53cf1dd0f8945
2014-04-16 16:43:05 +00:00
dan 22ace89179 Fix some problems to do with OOM conditions in vdbesort.c. Some problems remain.
FossilOrigin-Name: 2f94f9ce9bf11f1599bbc640b3fc8c15da588416
2014-04-15 20:52:27 +00:00
dan 1a088a8ef5 Fix further code and documentation issues in vdbesort.c.
FossilOrigin-Name: d03f5b8622d304f029f73c7cd0bee3182a81d081
2014-04-15 19:52:34 +00:00
dan 9c1586ec7c Allow the sorter to begin returning data to the VDBE as soon as it is available, instead of waiting until all keys have been sorted.
FossilOrigin-Name: cb0ab20c48962cdee03115efa93d7d501780ac73
2014-04-14 19:23:18 +00:00
dan f77ceba594 Improve performance in single-threaded mode by having the final merge pass keys directly to the VDBE, instead of going via a final PMA.
FossilOrigin-Name: 02610cd9b77caa2c181210056088beb3ad6ce30f
2014-04-14 18:41:21 +00:00
dan 92a20dde1f Minor fixes so that builds with SQLITE_MAX_WORKER_THREADS=0 work.
FossilOrigin-Name: e400bbbf26cdfe88f6cb231e96cdcddb9a6bcc0f
2014-04-14 08:45:32 +00:00
dan be3018c18f Improve use of multiple threads in sqlite3VdbeSorterRewind().
FossilOrigin-Name: e1bdc4b810907cc0e55e0c923c8ebc777068cfe0
2014-04-14 07:30:39 +00:00
dan 82a8a9f120 Fix many issues with new code.
FossilOrigin-Name: 62c406a042d7246f6df6b943421182a88483b2e3
2014-04-12 19:34:44 +00:00
dan 4be4c406fa Avoid having the sorter merge too many PMAs at a time when incrementally merging data following a SorterRewind().
FossilOrigin-Name: 98bf0307b121b0776a7170108cc8d3f948a7ebfe
2014-04-11 19:43:07 +00:00
dan d30ab3d9dd Experimental multi-threaded sorting changes to allow the sorter to begin returning items to the VDBE before all data is sorted.
FossilOrigin-Name: f9d5e09afaf64d68a0e461c1c2f38179bcea4b1f
2014-04-09 20:04:17 +00:00
drh bf20a35d5f Fix harmless compiler warnings.
FossilOrigin-Name: e54dded2012f0ab486ee138e9bd57c528af33980
2014-04-04 22:44:59 +00:00
mistachkin f7da5555da Fix typo in a Windows threading support routine.
FossilOrigin-Name: 5e3dfa27c71a666e122e3cf64897038ff8424800
2014-04-04 21:40:38 +00:00
drh 85462ed939 Merge the latest trunk changes into the threads branch.
FossilOrigin-Name: 39ac79cffe716f88af0871bdd206231b6a6511ff
2014-04-04 18:37:36 +00:00
dan 8daefc2af0 Add test file sort3.test, which should have been part of commit [9d3351b8d7].
FossilOrigin-Name: dceed2c803fca23c83c02c448d5ae7c4698efee1
2014-04-04 07:52:44 +00:00
drh 6b5d4759ce Change vdbeSorterExtendFile() so that it makes a best effort to create the
PMA file of the desired size, but does not return an error if unable.

FossilOrigin-Name: 217814bc4b53fab7bdad433e24e8aef8998c38fe
2014-04-04 02:13:26 +00:00
drh 1aca5caa88 Merge all recent changes from trunk.
FossilOrigin-Name: a0910079adde95245680dee59b43613b60903f10
2014-04-03 16:42:21 +00:00
dan 8930c2ab0c Fix an integer overflow problem in the sorter.
FossilOrigin-Name: 9d3351b8d713232133dad149c73fb2a27c72abb1
2014-04-03 16:25:29 +00:00
dan 6e4cc55e1f Fix minor errors causing compilation to fail with SQLITE_MAX_WORKER_THREADS set to a value greater than zero.
FossilOrigin-Name: 0561272abf357a2f4709f6c02866e570d19cd344
2014-04-03 14:29:08 +00:00
drh a634fb1577 Refactor local object and method names in vdbesort.c so that their names
more closely reflect their actual use.

FossilOrigin-Name: d284e30eb1db144965fa85566e4234e30464350b
2014-04-03 02:54:27 +00:00
drh ac4f0039c0 Add a big introductory comment to vdbesort.c explaining its operation at a
high level.  Also adjust some symbolic names and fix other comment issues in
that file.

FossilOrigin-Name: eef60f1bf54fcdc7b32f96ebb87a9a0bf0776e8b
2014-04-02 18:58:49 +00:00
dan dd95d30f82 Fix some problems with OOM handling in vdbesort.c.
FossilOrigin-Name: 47e702bd8392bc50c4edaf6a2c8c499af87b520e
2014-04-02 15:15:25 +00:00
drh 8d8f56296b Change the name of the SorterThread object to "SortSubtask" to avoid confusion
with the SQLiteThread object.

FossilOrigin-Name: 4ee2d910fbbed8d4def15e4e99ee225839f3a739
2014-04-02 14:38:14 +00:00
dan fad9f9a8a6 When sorting data for a CREATE INDEX statement in single-threaded mode, assume that keys are delivered to the sorter in primary key order. Also fix various comments that had fallen out of date.
FossilOrigin-Name: 821d1ac4504243fa13b9e3c0d56361ad9fb80d78
2014-04-01 18:41:51 +00:00
dan 578e1ca8d7 Even if compile time option SQLITE_MAX_WORKER_THREADS is set to one or greater, set the default number of worker threads to zero. Distribute data more evenly between threads in sqlite3VdbeSorterWrite() to improve performance when sorting large amounts of data. Add new test file sort2.test.
FossilOrigin-Name: 643c86a056168e39fcb7f39b8a72731f1eb246db
2014-04-01 15:38:44 +00:00
dan 38fdead890 Fix a problem with OOM handling in the sorter code.
FossilOrigin-Name: 59cd5229e2b5be5272cf57c7e7d09e97d16a5425
2014-04-01 10:19:02 +00:00
dan b3f56fdb69 Add the SQLITE_MAX_WORKER_THREADS compile time option. And the SQLITE_CONFIG_WORKER_THREADS sqlite3_config() switch.
FossilOrigin-Name: 2774710df8cd2bfaca49888c69f1b01c0ddadf9a
2014-03-31 19:57:34 +00:00
dan 853c4a7621 Fix a broken assert() in vdbesort.c.
FossilOrigin-Name: 18d1b402f2dbe78f1a1113bb356b710e348365ef
2014-03-29 10:01:58 +00:00
dan e7c84cc7e3 Fix a problem in vdbesort.c causing spurious SQLITE_NOMEM errors when using memsys3 or memsys5.
FossilOrigin-Name: a683c05f6250389e84b980b16559e162ba1a27c2
2014-03-29 09:34:45 +00:00
dan ff9fce4d60 Add the optimization to avoid some unnecessary calls to sqlite3VdbeRecordUnpack() added to the trunk by [707ea170b3].
FossilOrigin-Name: fc4d04e6b039ea5aeb47739e38c5926e63a4b01b
2014-03-29 06:27:35 +00:00
drh 73e7d8b2bb Fix a compiler warning and an after-OOM memory leak.
FossilOrigin-Name: 58f7ca29303c280229f86d01f418e1de5f5aebba
2014-03-28 19:47:19 +00:00
dan 2f17001521 Merge latest changes from orderby-planning branch.
FossilOrigin-Name: 4c7fb5423430f3b936befaa7c309f8e1968ee7d8
2014-03-28 19:18:16 +00:00
drh 7c8e9c78c8 Merge the latest changes from trunk.
FossilOrigin-Name: 3047a25f1c41e83f0b4772f7c36fbfec0f12dc7e
2014-03-28 18:35:39 +00:00
dan 6971952c65 Instead of allocating a single large buffer at the beginning of each sort operation, start with a small buffer and extend it using realloc() as required.
FossilOrigin-Name: 81987c8ceb64f051528a6ca42673821d9ab7c0ff
2014-03-27 19:25:02 +00:00
dan face087212 Use xFetch() to access temporary files in vdbesort.c. Use a single large allocation instead of many small allocations when accumulating records in vdbesort.c. This is an interim commit - it allocates a buffer the size of the page-cache every time data is sorted.
FossilOrigin-Name: f4ac1bf28c4ba395ccab8f1c9df72614a61095a7
2014-03-27 17:23:41 +00:00
drh bfa463696b Merge the latest trunk changes and the fix for the crash on a corrupt
database.

FossilOrigin-Name: 0b35346c32dba14963c85ec178f2b46aa2bbf6dc
2014-03-27 00:09:00 +00:00
drh 664eb14d8e Merge from trunk the fix for the crash on a corrupt database.
FossilOrigin-Name: 8cb2b02baa7ef9aa96319e977f0315328f944237
2014-03-26 19:45:01 +00:00
drh e6c7b09df6 Merge enhancements and fixes from trunk.
FossilOrigin-Name: e005f2d6dd9faf38cc8fdb9428b5aa6192a6adae
2014-03-25 18:29:12 +00:00
dan ab1dcc1a4b Fix a problem in the code added by [707ea170b3] causing vdbesort.c to sort unstably.
FossilOrigin-Name: d3e640afe611b6ae0b7f2cff5b00900d7e4d5ee3
2014-03-25 17:07:48 +00:00
dan 78d5843245 Remove the sequence values from sorter records used by ORDER BY as well.
FossilOrigin-Name: c3ae3697832a00d4d5758988a8766bdbb691e6b8
2014-03-25 15:04:07 +00:00
drh 3c863634ef Enable four sorting threads by default in the command-line shell.
FossilOrigin-Name: 1cab83577c814feb35b4fb91af0d52a9751d99bc
2014-03-25 14:12:16 +00:00
drh 5c2b314222 Merge all fixes and enhancements from trunk.
FossilOrigin-Name: b415dfb6cb0df0c69992ca2bb700c15664f158e6
2014-03-25 13:17:41 +00:00
dan dd23c6bfb4 Omit the sequence value from sorter records used by GROUP BY queries that cannot use an index.
FossilOrigin-Name: 3f90abddc31ac20739778c235a834c33f7057997
2014-03-24 20:19:07 +00:00
drh fd0a2f9756 Avoid unnecessary moving of content between registers during an ORDER BY.
FossilOrigin-Name: 4f472accf072d9cb64f209923924b26f21b13d27
2014-03-24 18:08:15 +00:00
dan 3f802ebce2 Remove an unnecessary temporary register allocation.
FossilOrigin-Name: 5d506743f541b022cde04a9606baa4680cdfd70b
2014-03-24 09:34:58 +00:00
drh 83553eefaf Remove a pointless OP_Once operation in ORDER BY clauses with LIMIT.
FossilOrigin-Name: e6c59d23316c83b318b1a94d9b28a5d321737fa5
2014-03-24 02:20:53 +00:00
drh 70f624c3a9 Further enhancements to geneverated VDBE code for ORDER BY.
FossilOrigin-Name: e7188fad87ec82d36a39b80ccaf8006bf45a9bcd
2014-03-24 01:43:50 +00:00
drh d345a66428 merge fixes from trunk
FossilOrigin-Name: faf7f9caf526ab33a6fdb9c89b45a0483510db21
2014-03-23 18:47:00 +00:00
drh f45f2326a2 Use only a single OP_MakeRecord instead of two when constructing entries
to go onto a sorter.

FossilOrigin-Name: d696cdedacd39075aa7fc407ab7c7e50f01d9f39
2014-03-23 17:45:03 +00:00
dan f87684189d Add an experimental multi-threaded capability to vdbesorter.c.
FossilOrigin-Name: ff0b5c851ba7d04d1836d7c6a3222713e7d8d357
2014-03-17 15:43:05 +00:00
dan c625ba7f4f Merge latest trunk changes into this branch.
FossilOrigin-Name: d17231b63d48c1f9c4dee109c90cec112e2f0fd4
2014-03-13 15:41:09 +00:00
drh 6ddecb753a Cherry-pick [555fc07]:
Changes to the thread routines to disable them when threading is turned
off using sqlite3_config().  Also merge all recent trunk changes.

FossilOrigin-Name: c92b0fe1371e7c20a5fbdf5fa96e30da14c40880
2012-08-21 17:36:44 +00:00
drh daa3ce4b08 Update the spellfix virtual table so that all OOM errors are reported out
to the application.

FossilOrigin-Name: c2cf498513c2633bd2b08372772eaa0f3b3ab25f
2012-08-21 13:08:15 +00:00
drh e22724ee54 Update the threads branch to include all the latest trunk changes.
FossilOrigin-Name: f4125771e21f1ca29d5442b5441dacfc06b8032b
2012-08-16 11:24:22 +00:00
mistachkin a806475f86 Add an assert() to help verify the return code from the Win32 thread wait function.
FossilOrigin-Name: ed3dc7a89f3416622fcd741ae5fba437929d06d6
2012-07-23 06:47:30 +00:00
mistachkin 572df3b1e4 Enhance implementation of the Win32 thread wait function.
FossilOrigin-Name: 049b04117353c3e163ffc87916cbe121403a2821
2012-07-23 02:00:38 +00:00
mistachkin da0e47109e Add Win32 support to the internal threads interface. Also, add several asserts and fix a few typos.
FossilOrigin-Name: 793195d37109c75eba84f7190c8fe0b8722f76f7
2012-07-21 22:49:08 +00:00
drh f51446a38c Add an internal interface that allows the code to take advantage of multiple
cores by pushing subcomputations off into separate threads.  The interface
is not currently used.

FossilOrigin-Name: 0e4d977a4a07d6de50acbf022c7dd947998b8d96
2012-07-21 19:40:42 +00:00
73 changed files with 5831 additions and 1772 deletions
+5 -1
View File
@@ -177,7 +177,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo \
table.lo threads.lo tokenize.lo trigger.lo \
update.lo util.lo vacuum.lo \
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
@@ -261,6 +261,7 @@ SRC = \
$(TOP)/src/sqliteInt.h \
$(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/threads.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
@@ -732,6 +733,9 @@ status.lo: $(TOP)/src/status.c $(HDR)
table.lo: $(TOP)/src/table.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/table.c
threads.lo: $(TOP)/src/threads.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/threads.c
tokenize.lo: $(TOP)/src/tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/tokenize.c
+5 -1
View File
@@ -564,7 +564,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
random.lo resolve.lo rowset.lo rtree.lo select.lo status.lo \
table.lo tokenize.lo trigger.lo \
table.lo threads.lo tokenize.lo trigger.lo \
update.lo util.lo vacuum.lo \
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
@@ -659,6 +659,7 @@ SRC = \
$(TOP)\src\sqliteInt.h \
$(TOP)\src\sqliteLimit.h \
$(TOP)\src\table.c \
$(TOP)\src\threads.c \
$(TOP)\src\tclsqlite.c \
$(TOP)\src\tokenize.c \
$(TOP)\src\trigger.c \
@@ -1139,6 +1140,9 @@ status.lo: $(TOP)\src\status.c $(HDR)
table.lo: $(TOP)\src\table.c $(HDR)
$(LTCOMPILE) -c $(TOP)\src\table.c
threads.lo: $(TOP)\src\threads.c $(HDR)
$(LTCOMPILE) -c $(TOP)\src\threads.c
tokenize.lo: $(TOP)\src\tokenize.c keywordhash.h $(HDR)
$(LTCOMPILE) -c $(TOP)\src\tokenize.c
+762 -734
View File
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -120,12 +120,13 @@ proc execsql_intout {sql} {
# Test that it is possible to open an existing database that contains
# r-tree tables.
#
do_test rtree-1.4.1 {
execsql {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
INSERT INTO t1 VALUES(1, 5.0, 10.0);
INSERT INTO t1 VALUES(2, 15.0, 20.0);
}
do_execsql_test rtree-1.4.1a {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
INSERT INTO t1 VALUES(1, 5.0, 10.0);
SELECT substr(hex(data),1,40) FROM t1_node;
} {00000001000000000000000140A0000041200000}
do_execsql_test rtree-1.4.1b {
INSERT INTO t1 VALUES(2, 15.0, 20.0);
} {}
do_test rtree-1.4.2 {
db close
@@ -435,16 +436,18 @@ do_test rtree-11.2 {
# Test on-conflict clause handling.
#
db_delete_and_reopen
do_execsql_test 12.0 {
do_execsql_test 12.0.1 {
CREATE VIRTUAL TABLE t1 USING rtree_i32(idx, x1, x2, y1, y2);
INSERT INTO t1 VALUES(1, 1, 2, 3, 4);
SELECT substr(hex(data),1,56) FROM t1_node;
} {00000001000000000000000100000001000000020000000300000004}
do_execsql_test 12.0.2 {
INSERT INTO t1 VALUES(2, 2, 3, 4, 5);
INSERT INTO t1 VALUES(3, 3, 4, 5, 6);
CREATE TABLE source(idx, x1, x2, y1, y2);
INSERT INTO source VALUES(5, 8, 8, 8, 8);
INSERT INTO source VALUES(2, 7, 7, 7, 7);
}
db_save_and_close
foreach {tn sql_template testdata} {
+9 -9
View File
@@ -57,31 +57,31 @@ do_test rtree6-1.1 {
do_test rtree6-1.2 {
rtree_strategy {SELECT * FROM t1 WHERE x1>10}
} {Ea}
} {E0}
do_test rtree6-1.3 {
rtree_strategy {SELECT * FROM t1 WHERE x1<10}
} {Ca}
} {C0}
do_test rtree6-1.4 {
rtree_strategy {SELECT * FROM t1,t2 WHERE k=ii AND x1<10}
} {Ca}
} {C0}
do_test rtree6-1.5 {
rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10}
} {Ca}
} {C0}
do_eqp_test rtree6.2.1 {
SELECT * FROM t1,t2 WHERE k=+ii AND x1<10
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
}
do_eqp_test rtree6.2.2 {
SELECT * FROM t1,t2 WHERE k=ii AND x1<10
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:Ca}
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0}
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
}
@@ -95,7 +95,7 @@ do_eqp_test rtree6.2.3 {
do_eqp_test rtree6.2.4 {
SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10
} {
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:CaEb}
0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1}
0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)}
}
@@ -126,7 +126,7 @@ do_test rtree6.3.2 {
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
}
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
do_test rtree6.3.3 {
rtree_strategy {
SELECT * FROM t3 WHERE
@@ -137,7 +137,7 @@ do_test rtree6.3.3 {
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND
x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5
}
} {EaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEaEa}
} {E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0}
do_execsql_test rtree6-3.4 {
SELECT * FROM t3 WHERE x1>0.5 AND x1>0.8 AND x1>1.1
+1 -1
View File
@@ -41,7 +41,7 @@ ifcapable rtree_int_only {
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
SELECT rtreenode(2, data) FROM t1_node;
}
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
} {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}}
}
finish_test
+6 -7
View File
@@ -29,7 +29,7 @@ do_eqp_test 1.1 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
} {
0 0 1 {SCAN TABLE t}
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 1.2 {
@@ -37,7 +37,7 @@ do_eqp_test 1.2 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
} {
0 0 0 {SCAN TABLE t}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 1.3 {
@@ -45,7 +45,7 @@ do_eqp_test 1.3 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
} {
0 0 0 {SCAN TABLE t}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 1.5 {
@@ -82,7 +82,7 @@ do_eqp_test 2.1 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
} {
0 0 1 {SCAN TABLE t}
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 2.2 {
@@ -90,7 +90,7 @@ do_eqp_test 2.2 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y
} {
0 0 0 {SCAN TABLE t}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 2.3 {
@@ -98,7 +98,7 @@ do_eqp_test 2.3 {
WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y
} {
0 0 0 {SCAN TABLE t}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:DdBcDbBa}
0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0}
}
do_eqp_test 2.5 {
@@ -271,4 +271,3 @@ ifcapable rtree {
finish_test
+129
View File
@@ -0,0 +1,129 @@
# 2010 August 28
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file contains tests for the r-tree module. Specifically, it tests
# that new-style custom r-tree queries (geometry callbacks) work.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return }
ifcapable rtree_int_only { finish_test; return }
#-------------------------------------------------------------------------
# Test the example 2d "circle" geometry callback.
#
register_circle_geom db
do_execsql_test rtreeE-1.1 {
PRAGMA page_size=512;
CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1);
/* A tight pattern of small boxes near 0,0 */
WITH RECURSIVE
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
INSERT INTO rt1 SELECT x+5*y, x, x+2, y, y+2 FROM x, y;
/* A looser pattern of small boxes near 100, 0 */
WITH RECURSIVE
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
INSERT INTO rt1 SELECT 100+x+5*y, x*3+100, x*3+102, y*3, y*3+2 FROM x, y;
/* A looser pattern of larger boxes near 0, 200 */
WITH RECURSIVE
x(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM x WHERE x<4),
y(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM y WHERE y<4)
INSERT INTO rt1 SELECT 200+x+5*y, x*7, x*7+15, y*7+200, y*7+215 FROM x, y;
} {}
# Queries against each of the three clusters */
do_execsql_test rtreeE-1.1 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 0.0, 50.0, 3) ORDER BY id;
} {0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24}
do_execsql_test rtreeE-1.2 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(100.0, 0.0, 50.0, 3) ORDER BY id;
} {100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124}
do_execsql_test rtreeE-1.3 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(0.0, 200.0, 50.0, 3) ORDER BY id;
} {200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224}
# The Qcircle geometry function gives a lower score to larger leaf-nodes.
# This causes the 200s to sort before the 100s and the 0s to sort before
# last.
#
do_execsql_test rtreeE-1.4 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,3) AND id%100==0
} {200 100 0}
# Exclude odd rowids on a depth-first search
do_execsql_test rtreeE-1.5 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,4) ORDER BY +id
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
# Exclude odd rowids on a breadth-first search.
do_execsql_test rtreeE-1.6 {
SELECT id FROM rt1 WHERE id MATCH Qcircle(0,0,1000,5) ORDER BY +id
} {0 2 4 6 8 10 12 14 16 18 20 22 24 100 102 104 106 108 110 112 114 116 118 120 122 124 200 202 204 206 208 210 212 214 216 218 220 222 224}
# Construct a large 2-D RTree with thousands of random entries.
#
do_test rtreeE-2.1 {
db eval {
CREATE TABLE t2(id,x0,x1,y0,y1);
CREATE VIRTUAL TABLE rt2 USING rtree(id,x0,x1,y0,y1);
BEGIN;
}
expr srand(0)
for {set i 1} {$i<=10000} {incr i} {
set dx [expr {int(rand()*40)+1}]
set dy [expr {int(rand()*40)+1}]
set x0 [expr {int(rand()*(10000 - $dx))}]
set x1 [expr {$x0+$dx}]
set y0 [expr {int(rand()*(10000 - $dy))}]
set y1 [expr {$y0+$dy}]
set id [expr {$i+10000}]
db eval {INSERT INTO t2 VALUES($id,$x0,$x1,$y0,$y1)}
}
db eval {
INSERT INTO rt2 SELECT * FROM t2;
COMMIT;
}
} {}
for {set i 1} {$i<=200} {incr i} {
set dx [expr {int(rand()*100)}]
set dy [expr {int(rand()*100)}]
set x0 [expr {int(rand()*(10000 - $dx))}]
set x1 [expr {$x0+$dx}]
set y0 [expr {int(rand()*(10000 - $dy))}]
set y1 [expr {$y0+$dy}]
set ans [db eval {SELECT id FROM t2 WHERE x1>=$x0 AND x0<=$x1 AND y1>=$y0 AND y0<=$y1 ORDER BY id}]
do_execsql_test rtreeE-2.2.$i {
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ORDER BY id
} $ans
}
# Run query that have very deep priority queues
#
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=5000 AND y1>=0 AND y0<=5000 ORDER BY id}]
do_execsql_test rtreeE-2.3 {
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,5000,0,5000) ORDER BY id
} $ans
set ans [db eval {SELECT id FROM t2 WHERE x1>=0 AND x0<=10000 AND y1>=0 AND y0<=10000 ORDER BY id}]
do_execsql_test rtreeE-2.4 {
SELECT id FROM rt2 WHERE id MATCH breadthfirstsearch(0,10000,0,10000) ORDER BY id
} $ans
finish_test
+61 -6
View File
@@ -21,6 +21,16 @@ extern "C" {
#endif
typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
typedef struct sqlite3_rtree_query_info sqlite3_rtree_query_info;
/* The double-precision datatype used by RTree depends on the
** SQLITE_RTREE_INT_ONLY compile-time option.
*/
#ifdef SQLITE_RTREE_INT_ONLY
typedef sqlite3_int64 sqlite3_rtree_dbl;
#else
typedef double sqlite3_rtree_dbl;
#endif
/*
** Register a geometry callback named zGeom that can be used as part of an
@@ -31,11 +41,7 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
int sqlite3_rtree_geometry_callback(
sqlite3 *db,
const char *zGeom,
#ifdef SQLITE_RTREE_INT_ONLY
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
#else
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
#endif
int (*xGeom)(sqlite3_rtree_geometry*, int, sqlite3_rtree_dbl*,int*),
void *pContext
);
@@ -47,11 +53,60 @@ int sqlite3_rtree_geometry_callback(
struct sqlite3_rtree_geometry {
void *pContext; /* Copy of pContext passed to s_r_g_c() */
int nParam; /* Size of array aParam[] */
double *aParam; /* Parameters passed to SQL geom function */
sqlite3_rtree_dbl *aParam; /* Parameters passed to SQL geom function */
void *pUser; /* Callback implementation user data */
void (*xDelUser)(void *); /* Called by SQLite to clean up pUser */
};
/*
** Register a 2nd-generation geometry callback named zScore that can be
** used as part of an R-Tree geometry query as follows:
**
** SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zQueryFunc(... params ...)
*/
int sqlite3_rtree_query_callback(
sqlite3 *db,
const char *zQueryFunc,
int (*xQueryFunc)(sqlite3_rtree_query_info*),
void *pContext,
void (*xDestructor)(void*)
);
/*
** A pointer to a structure of the following type is passed as the
** argument to scored geometry callback registered using
** sqlite3_rtree_query_callback().
**
** Note that the first 5 fields of this structure are identical to
** sqlite3_rtree_geometry. This structure is a subclass of
** sqlite3_rtree_geometry.
*/
struct sqlite3_rtree_query_info {
void *pContext; /* pContext from when function registered */
int nParam; /* Number of function parameters */
sqlite3_rtree_dbl *aParam; /* value of function parameters */
void *pUser; /* callback can use this, if desired */
void (*xDelUser)(void*); /* function to free pUser */
sqlite3_rtree_dbl *aCoord; /* Coordinates of node or entry to check */
unsigned int *anQueue; /* Number of pending entries in the queue */
int nCoord; /* Number of coordinates */
int iLevel; /* Level of current node or entry */
int mxLevel; /* The largest iLevel value in the tree */
sqlite3_int64 iRowid; /* Rowid for current entry */
sqlite3_rtree_dbl rParentScore; /* Score of parent node */
int eParentWithin; /* Visibility of parent node */
int eWithin; /* OUT: Visiblity */
sqlite3_rtree_dbl rScore; /* OUT: Write the score here */
};
/*
** Allowed values for sqlite3_rtree_query.eWithin and .eParentWithin.
*/
#define NOT_WITHIN 0 /* Object completely outside of query region */
#define PARTLY_WITHIN 1 /* Object partially overlaps query region */
#define FULLY_WITHIN 2 /* Object fully contained within query region */
#ifdef __cplusplus
} /* end of the 'extern "C"' block */
+4 -2
View File
@@ -66,7 +66,7 @@ LIBOBJ+= vdbe.o parse.o \
notify.o opcodes.o os.o os_unix.o os_win.o \
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
random.o resolve.o rowset.o rtree.o select.o status.o \
table.o tokenize.o trigger.o \
table.o threads.o tokenize.o trigger.o \
update.o util.o vacuum.o \
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
@@ -144,6 +144,7 @@ SRC = \
$(TOP)/src/sqliteLimit.h \
$(TOP)/src/table.c \
$(TOP)/src/tclsqlite.c \
$(TOP)/src/threads.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/trigger.c \
$(TOP)/src/utf.c \
@@ -311,6 +312,7 @@ TESTSRC2 = \
$(TOP)/src/pcache.c \
$(TOP)/src/pcache1.c \
$(TOP)/src/select.c \
$(TOP)/src/threads.c \
$(TOP)/src/tokenize.c \
$(TOP)/src/utf.c \
$(TOP)/src/util.c \
@@ -476,7 +478,7 @@ parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
mv parse.h parse.h.temp
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest.uuid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
keywordhash.h: $(TOP)/tool/mkkeywordhash.c
+77 -70
View File
@@ -1,9 +1,9 @@
C Enhancements\sto\sthe\sdate\sand\stime\sfunctions\sso\sthat\sthey\soptionally\ssupport\na\s5-digit\syear.\s\sNot\ssure\swe\swant\sto\sinclude\sthis\sin\strunk.\s\sSaved\sin\sa\sbranch\nfor\sfuture\sreference.
D 2014-04-23T12:00:20.142
C Fix\sseveral\sharmless\scompiler\swarnings.
D 2014-05-09T00:36:06.204
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.msc fdacba6fb574868c71fde6db6b77789a383a4c19
F Makefile.msc 7d6981e8e14d8189a2a2f9b4a485f40b2032cb2e
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
F VERSION 9f823c026c6a32fc5f84d212a8aae0a221dba45c
@@ -120,30 +120,31 @@ F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
F ext/rtree/rtree.c 6f70db93e0e42c369325c5cddcf2024c5a87ca43
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
F ext/rtree/rtree1.test e2da4aaa426918d27122d1a1066c6ecf8409a514
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
F ext/rtree/rtree6.test fe0bd377a21c68ce2826129d14354c884cb1f354
F ext/rtree/rtree6.test 756585abc51727fec97c77852476445c10c0ee95
F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a
F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
F ext/rtree/rtreeC.test 16d7aa86ecb6a876d2a38cf590a1471a41b3a46d
F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e
F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
F ext/rtree/rtreeE.test 388c1c8602c3ce55c15f03b509e9cf545fb7c41f
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
F ext/rtree/sqlite3rtree.h 83349d519fe5f518b3ea025d18dd1fe51b1684bd
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
F main.mk 3ae543fa446525c1dec55f58de67f41b78651812
F main.mk f51f401a87fd07be255bcecae8b03105ca2024e8
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -158,35 +159,35 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
F src/analyze.c 663e0b291d27eb03c9fd6b421e2d61ba348a2389
F src/analyze.c 3596f863bb80126fe56ba217df5932749271efc8
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 6c9b51abd404ce5b78b173b6f2248e8cb824758c
F src/btree.c e14daeed62b5b1499835a6523f9a47d660c297c8
F src/btree.h d79306df4ed9181b48916737fe8871a4392c4594
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
F src/build.c 5bfeea8f302ec2926c9eea321a61daea92a29fa4
F src/build.c 9c522b6e5af1485c38b12a55f9d946e66fca61b6
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
F src/date.c 483fd9eeb74e06c2ddc4b33ade4a8a9611230386
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c bcf8f72126cea80fc3d5bc5494cf19b3f8935aaf
F src/expr.c 4f9e497c66e2f25a4d139357a778c84d5713207c
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
F src/global.c b7943ff485c31660ec0b17c68467034804df01b1
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c d8bb30535c8c0785876025a4a07f9074640a15d1
F src/insert.c ab34bea5af4fee9f956a0805a32463fb7f674d00
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c 0a8cfb6b2899649880e5874ac9bfd1c6f7c6a4a3
F src/main.c 2ba4f6eeb84cf8efd8bb632c1abe203dc86adcac
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
@@ -194,40 +195,40 @@ F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
F src/mutex_w32.c 6108c88e1cb38d8fbb3534b170793815cbedbf97
F src/mutex_noop.c 4222773e5f61e506f232aedc9ad9e16ca00c1399
F src/mutex_unix.c 56e22c1bc6aabfa2f9736317a8f56acd5d0c5f7c
F src/mutex_w32.c c4726d3bfe80996665a39d27598ebd056e2d6b89
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e
F src/os_win.c 5024065c68c50739aeef6d490db88e5b682fcc30
F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
F src/pragma.c 21ece94d4f3e76e8e150deecafb9c7abd398ec67
F src/pragma.c 810ef31ccfaa233201dcf100637a9777cc24e897
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
F src/select.c bc7feff0fb4c4a1b9d655b717bef166846b48e33
F src/shell.c 2afe7a7154e97be0c74c5feacf09626bda8493be
F src/sqlite.h.in bde98816e1ba0c9ffef50afe7b32f4e5a8f54fe0
F src/select.c a5ed3fdc82ebab5b9b095ea1971515a7f8a303d2
F src/shell.c 6946aea9f21af551fa84bc6b2a8de55d93bf0004
F src/sqlite.h.in ed6d0cc90da850340c3863c84351e6e164c0ef00
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 03e2f60ccb0745fa2d3a072cb4f75fa29251d2ee
F src/sqliteInt.h 851003126071d4a3bac86a0db75c48197fbd0ff0
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
F src/test1.c a0e59104fec5626bb1d1bd746157f43e85245e4b
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -240,7 +241,7 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585
F src/test_config.c bf2e0bf49ebd8fe3dccabb4542157f9571fe48fa
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@ -251,7 +252,7 @@ F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
F src/test_malloc.c 27047a841f5bff1cb638123806a2c30714771307
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
@@ -260,7 +261,7 @@ F src/test_osinst.c 90a845c8183013d80eccb1f29e8805608516edba
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0
F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb
F src/test_rtree.c f3d1d12538dccb75fd916e3fa58f250edbdd3b47
F src/test_rtree.c fdd8d29ca5165c7857987a2ba263fac5c69e231f
F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6
F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
@@ -270,29 +271,30 @@ F src/test_syscall.c 2e21ca7f7dc54a028f1967b63f1e76155c356f9b
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c b9daffcb6ae3a9c080da37b905e790d45a8f99db
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
F src/util.c 2b5fb283a190aacdb286f7835a447c45b345b83c
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c bf284edea1cee0508dc93c79a73498e0f317edb7
F src/vdbe.c 89ab2ded5123e823b47293aedd7931a4742fb6bd
F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
F src/vdbeInt.h e6d83e5bfd62fc6685ba1ed6153f7099f82de9f7
F src/vdbeInt.h c78ace64dc37495806dd50596eded1f6cd2b5a64
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
F src/vdbeaux.c e493f38758c4b8f4ca2007cf6a700bd405d192f3
F src/vdbeaux.c 44d4d1f5711f71eaf0d624de5c3e4976fe4e180b
F src/vdbeblob.c 9205ce9d3b064d9600f8418a897fc88b5687d9ac
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
F src/vdbesort.c 4abb7c0f8f19b7d7d82f4558d5da1a30fdf9ea38
F src/vdbesort.c b36070436d33372237541e9eaa6068e1a61bc402
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c 3b127bdc24b7aa84ffa69729170be11555cd7733
F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6
F src/where.c 91dfd382273c3f67fcdc0ac4728f9140f91c6ab3
F src/whereInt.h 6804c2e5010378568c2bb1350477537755296a46
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -305,13 +307,13 @@ F test/alter4.test d6c011fa0d6227abba762498cafbb607c9609e93
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f
F test/analyze.test 1772936d66471c65221e437b6d1999c3a03166c4
F test/analyze3.test 412f690dfe95b337475e3e78a84a85d25f6f125d
F test/analyze3.test bf41f0f680dd1e0d44eed5e769531e93a5320275
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
F test/analyze9.test e072a5172d55afcba98d6ca6a219ce8878c2f5c9
F test/analyze9.test 623e02a99a78fa12fe5def2fd559032d5d887e0f
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
@@ -329,7 +331,7 @@ F test/auth.test 5bdf154eb28c0e4bbc0473f335858c0d96171768
F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e
F test/autoindex1.test 762ff3f8e25d852aae55c6462ca166a80c0cde61
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
@@ -406,6 +408,7 @@ F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
F test/corruptI.test b3e4203d420490fc3d3062711597bc1dea06a789
F test/cost.test 04842adec34311d70c3f3c5fd698b22be54138fd
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
@@ -433,12 +436,12 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
F test/e_createtable.test ed82efcedc4b3656b27a5fcd12335cdb7e20eeee
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
F test/e_fkey.test 630597377549af579d34faaf64c6959a5a68ef76
F test/e_fkey.test a1783fe1f759e1990e6a11adfcf0702dac4d0707
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
F test/e_reindex.test 396b7b4f0a66863b4e95116a67d93b227193e589
@@ -452,7 +455,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac
F test/eqp.test 90b56d03a93a2e7bb90f88be6083a8ea53f11a0e
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75
@@ -610,7 +613,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
F test/index3.test 55a90cff99834305e8141df7afaef39674b57062
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
F test/index6.test a0a2d286ffa6d35813f5003fdb7be124825b4422
F test/index6.test fb370966ac3cd0989053dd5385757b5c3e24ab6a
F test/index7.test a3baf9a625bda7fd49471e99aeae04095fbfeecf
F test/indexedby.test b2f22f3e693a53813aa3f50b812eb609ba6df1ec
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
@@ -662,7 +665,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
F test/malloc.test ada8ae15193ffc6415bf431a6db31d4ec507dbfe
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
@@ -670,7 +673,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e
F test/mallocA.test 1ba0367fb5434e7bc2fa4afcb30b14174d91b160
F test/mallocA.test c049224adeb0244b8f6eb770c1fa6ac40f9b3518
F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be
F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6
F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4
@@ -722,8 +725,9 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
F test/orderby5.test 2490183fef54417209d1df253633a605d46bd350
F test/orderby5.test 8f08a54836d21fb7c70245360751aedd1c2286fb
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
@@ -737,7 +741,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
F test/permutations.test 33e7e239ba494fdb30e2f4ffc64c508b145ff42f
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@@ -786,7 +790,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
F test/selectA.test 64b88a80271c1710966e50e633380696b60a12a4
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
@@ -810,13 +814,18 @@ F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
F test/skipscan2.test d77f79cdbba25f0f6f35298136cff21a7d7a553a
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/sort.test 688468cef8c9a66fcc1d54235de8e4deac745690
F test/sort2.test c5e25eb674689e291d06b5209fe8d337ae0ec010
F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2
F test/sort4.test 971452fd4e2928e6fc05c3868396ad7d5f9ce2ad
F test/sortfault.test 1a12b6e27d475f50658a8164aaa34f0080a86b36
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
@@ -825,7 +834,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
F test/speedtest1.c f452891e50571627f7060c0e1262359127055717
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
@@ -845,7 +854,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl f31bea1483ea1d39620f982130026e76f872d744
F test/tester.tcl bc0889a2f86d9c17307992ca1e70391794780265
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -905,6 +914,7 @@ F test/tkt-d11f09d36e.test d999b548fef885d1d1afa49a0e8544ecf436869d
F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00
F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9
F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2
F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead
@@ -1022,7 +1032,7 @@ F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unixexcl.test cd6c765f75e50e8e2c2ba763149e5d340ea19825
F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c
F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
F test/uri.test 23662b7b61958b0f0e47082de7d06341ccf85d5b
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
@@ -1052,7 +1062,7 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
@@ -1079,7 +1089,7 @@ F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
F test/where.test 28b64e93428961b07b0d486778d63fd672948f6b
F test/where2.test 455a2eb2666e66c1e84e2cb5815173a85e6237db
F test/where3.test d28c51f257e60be30f74308fa385ceeddfb54a6e
F test/where3.test 1ad55ba900bd7747f98b6082e65bd3e442c5004e
F test/where4.test d8420ceeb8323a41ceff1f1841fc528e824e1ecf
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
@@ -1093,7 +1103,7 @@ F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
F test/whereD.test fd9120e262f9da3c45940f52aefeef4d15b904e5
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344
F test/whereG.test 0ac23e5e8311b69d87245f4a85112de321031658
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
@@ -1123,14 +1133,14 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/lemon.c 07aba6270d5a5016ba8107b09e431eea4ecdc123
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
F tool/logest.c 388c318c7ac8b52b7c08ca1e2de0f4ca9a8f7e81
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
F tool/mkautoconfamal.sh f8d8dbf7d62f409ebed5134998bf5b51d7266383
F tool/mkkeywordhash.c c9e05e4a7bcab8fab9f583d5b321fb72f565ad97
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e
F tool/mkpragmatab.tcl 78a77b2c554d534c6f2dc903130186ed15715460
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F tool/mksqlite3c-noext.tcl 8bce31074e4cbe631bb7676526a048335f4c9f02
F tool/mksqlite3c.tcl ed5b4e9ca8bf209ff401059a16362f37710fd8b8
F tool/mksqlite3c-noext.tcl 752f1a9d3287f6c0ef5738b1c4add0b96fbe0854
F tool/mksqlite3c.tcl 8da823522f27608494997e1dba19cd426572ba80
F tool/mksqlite3h.tcl ba24038056f51fde07c0079c41885ab85e2cff12
F tool/mksqlite3internalh.tcl 3dca7bb5374cee003379b8cbac73714f610ef795
F tool/mkvsix.tcl 6477fb9dab838b7eea1eed50658ff1cda04850b5
@@ -1161,10 +1171,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 65d2544af9adc1e2f1d193e57f8be0422fb0d5eb
R 65a7ac109a1878f6dcc92cd296f64cbc
T *branch * five-digit-year
T *sym-five-digit-year *
T -sym-trunk *
U drh
Z 20a358e6aab334ebda712a29750f60b8
P dc7f84dfcc8415fad4af041fd30c20b3fd91be45
R dab57784c4183d6467c4fe813ebf5ee5
U mistachkin
Z bd4d9a5acb160a48faa7ad2a8521ce0e
+1 -1
View File
@@ -1 +1 @@
2029a396dcdb928f79780ec80c808fda6e3285a1
360c0fd1cf9db5f1e4f670a4b95971daaeaa5879
+18 -7
View File
@@ -1371,6 +1371,7 @@ static void decodeIntArray(
char *zIntArray, /* String containing int array to decode */
int nOut, /* Number of slots in aOut[] */
tRowcnt *aOut, /* Store integers here */
LogEst *aLog, /* Or, if aOut==0, here */
Index *pIndex /* Handle extra flags for this index, if not NULL */
){
char *z = zIntArray;
@@ -1389,7 +1390,17 @@ static void decodeIntArray(
v = v*10 + c - '0';
z++;
}
aOut[i] = v;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( aOut ){
aOut[i] = v;
}else
#else
assert( aOut==0 );
UNUSED_PARAMETER(aOut);
#endif
{
aLog[i] = sqlite3LogEst(v);
}
if( *z==' ' ) z++;
}
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -1445,12 +1456,12 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
z = argv[2];
if( pIndex ){
decodeIntArray((char*)z, pIndex->nKeyCol+1, pIndex->aiRowEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowEst = pIndex->aiRowEst[0];
decodeIntArray((char*)z, pIndex->nKeyCol+1, 0, pIndex->aiRowLogEst, pIndex);
if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0];
}else{
Index fakeIdx;
fakeIdx.szIdxRow = pTable->szTabRow;
decodeIntArray((char*)z, 1, &pTable->nRowEst, &fakeIdx);
decodeIntArray((char*)z, 1, 0, &pTable->nRowLogEst, &fakeIdx);
pTable->szTabRow = fakeIdx.szIdxRow;
}
@@ -1642,9 +1653,9 @@ static int loadStatTbl(
pPrevIdx = pIdx;
}
pSample = &pIdx->aSample[pIdx->nSample];
decodeIntArray((char*)sqlite3_column_text(pStmt,1), nCol, pSample->anEq, 0);
decodeIntArray((char*)sqlite3_column_text(pStmt,2), nCol, pSample->anLt, 0);
decodeIntArray((char*)sqlite3_column_text(pStmt,3), nCol, pSample->anDLt,0);
decodeIntArray((char*)sqlite3_column_text(pStmt,1),nCol,pSample->anEq,0,0);
decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
/* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
+6 -3
View File
@@ -4609,7 +4609,7 @@ int sqlite3BtreeMovetoUnpacked(
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
pIdxKey->isCorrupt = 0;
pIdxKey->errCode = 0;
assert( pIdxKey->default_rc==1
|| pIdxKey->default_rc==0
|| pIdxKey->default_rc==-1
@@ -4733,7 +4733,10 @@ int sqlite3BtreeMovetoUnpacked(
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
sqlite3_free(pCellKey);
}
assert( pIdxKey->isCorrupt==0 || c==0 );
assert(
(pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
&& (pIdxKey->errCode!=SQLITE_NOMEM || pCur->pBtree->db->mallocFailed)
);
if( c<0 ){
lwr = idx+1;
}else if( c>0 ){
@@ -4743,7 +4746,7 @@ int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
rc = SQLITE_OK;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
goto moveto_finish;
}
if( lwr>upr ) break;
+28 -21
View File
@@ -905,7 +905,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
pTable->nRowEst = 1048576;
pTable->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
assert( pParse->pNewTable==0 );
pParse->pNewTable = pTable;
@@ -2669,7 +2669,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
/* Open the sorter cursor if we are to use one. */
iSorter = pParse->nTab++;
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, 0, (char*)
sqlite3VdbeAddOp4(v, OP_SorterOpen, iSorter, 0, pIndex->nKeyCol, (char*)
sqlite3KeyInfoRef(pKey), P4_KEYINFO);
/* Open the table. Loop through all rows of the table, inserting index
@@ -2730,15 +2730,15 @@ Index *sqlite3AllocateIndexObject(
nByte = ROUND8(sizeof(Index)) + /* Index structure */
ROUND8(sizeof(char*)*nCol) + /* Index.azColl */
ROUND8(sizeof(tRowcnt)*(nCol+1) + /* Index.aiRowEst */
ROUND8(sizeof(LogEst)*(nCol+1) + /* Index.aiRowLogEst */
sizeof(i16)*nCol + /* Index.aiColumn */
sizeof(u8)*nCol); /* Index.aSortOrder */
p = sqlite3DbMallocZero(db, nByte + nExtra);
if( p ){
char *pExtra = ((char*)p)+ROUND8(sizeof(Index));
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
p->aiRowEst = (tRowcnt*)pExtra; pExtra += sizeof(tRowcnt)*(nCol+1);
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
p->azColl = (char**)pExtra; pExtra += ROUND8(sizeof(char*)*nCol);
p->aiRowLogEst = (LogEst*)pExtra; pExtra += sizeof(LogEst)*(nCol+1);
p->aiColumn = (i16*)pExtra; pExtra += sizeof(i16)*nCol;
p->aSortOrder = (u8*)pExtra;
p->nColumn = nCol;
p->nKeyCol = nCol - 1;
@@ -2968,7 +2968,7 @@ Index *sqlite3CreateIndex(
if( db->mallocFailed ){
goto exit_create_index;
}
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowLogEst) );
assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
pIndex->zName = zExtra;
zExtra += nName + 1;
@@ -3018,7 +3018,7 @@ Index *sqlite3CreateIndex(
pParse->checkSchema = 1;
goto exit_create_index;
}
assert( pTab->nCol<=0x7fff && j<=0x7fff );
assert( j<=0x7fff );
pIndex->aiColumn[i] = (i16)j;
if( pListItem->pExpr ){
int nColl;
@@ -3249,7 +3249,7 @@ exit_create_index:
** Since we do not know, guess 1 million. aiRowEst[1] is an estimate of the
** number of rows in the table that match any particular value of the
** first column of the index. aiRowEst[2] is an estimate of the number
** of rows that match any particular combiniation of the first 2 columns
** of rows that match any particular combination of the first 2 columns
** of the index. And so forth. It must always be the case that
*
** aiRowEst[N]<=aiRowEst[N-1]
@@ -3260,20 +3260,27 @@ exit_create_index:
** are based on typical values found in actual indices.
*/
void sqlite3DefaultRowEst(Index *pIdx){
tRowcnt *a = pIdx->aiRowEst;
/* 10, 9, 8, 7, 6 */
LogEst aVal[] = { 33, 32, 30, 28, 26 };
LogEst *a = pIdx->aiRowLogEst;
int nCopy = MIN(ArraySize(aVal), pIdx->nKeyCol);
int i;
tRowcnt n;
assert( a!=0 );
a[0] = pIdx->pTable->nRowEst;
if( a[0]<10 ) a[0] = 10;
n = 10;
for(i=1; i<=pIdx->nKeyCol; i++){
a[i] = n;
if( n>5 ) n--;
}
if( pIdx->onError!=OE_None ){
a[pIdx->nKeyCol] = 1;
/* Set the first entry (number of rows in the index) to the estimated
** number of rows in the table. Or 10, if the estimated number of rows
** in the table is less than that. */
a[0] = pIdx->pTable->nRowLogEst;
if( a[0]<33 ) a[0] = 33; assert( 33==sqlite3LogEst(10) );
/* Estimate that a[1] is 10, a[2] is 9, a[3] is 8, a[4] is 7, a[5] is
** 6 and each subsequent value (if any) is 5. */
memcpy(&a[1], aVal, nCopy*sizeof(LogEst));
for(i=nCopy+1; i<=pIdx->nKeyCol; i++){
a[i] = 23; assert( 23==sqlite3LogEst(5) );
}
assert( 0==sqlite3LogEst(1) );
if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0;
}
/*
+26 -51
View File
@@ -229,7 +229,7 @@ static void computeJD(DateTime *p){
}
A = Y/100;
B = 2 - A + (A/4);
X1 = 365*(Y+4716) + 25*(Y+4716)/100;
X1 = 36525*(Y+4716)/100;
X2 = 306001*(M+1)/10000;
p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000);
p->validJD = 1;
@@ -258,23 +258,18 @@ static void computeJD(DateTime *p){
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
int Y, M, D, neg;
char c;
if( zDate[0]=='-' ){
zDate++;
neg = 1;
}else{
neg = 0;
if( zDate[0]=='+' ) zDate++;
}
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)==3 ){
zDate += 10;
}else if( getDigits(zDate,5,0,99999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)==3 ){
zDate += 11;
}else{
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
return 1;
}
while( (c = zDate[0])=='T' || c=='t' || sqlite3Isspace(c) ){ zDate++; }
zDate += 10;
while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; }
if( parseHhMmSs(zDate, p)==0 ){
/* We got the time */
}else if( *zDate==0 ){
@@ -360,7 +355,7 @@ static void computeYMD(DateTime *p){
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (int)((B - 122.1)/365.25);
D = 365*C + (25*C)/100;
D = (36525*C)/100;
E = (int)((B-D)/30.6001);
X1 = (int)(30.6001*E);
p->D = B - D - X1;
@@ -582,8 +577,19 @@ static int parseModifier(sqlite3_context *pCtx, const char *zMod, DateTime *p){
}
#endif
case 'u': {
/*
** unixepoch
**
** Treat the current value of p->iJD as the number of
** seconds since 1970. Convert to a real julian day number.
*/
if( strcmp(z, "unixepoch")==0 && p->validJD ){
p->iJD = (p->iJD + 43200)/86400 + 21086676*(i64)10000000;
clearYMD_HMS_TZ(p);
rc = 0;
}
#ifndef SQLITE_OMIT_LOCALTIME
if( strcmp(z, "utc")==0 ){
else if( strcmp(z, "utc")==0 ){
sqlite3_int64 c1;
computeJD(p);
c1 = localtimeOffset(p, pCtx, &rc);
@@ -755,7 +761,7 @@ static int isDate(
sqlite3_value **argv,
DateTime *p
){
int i = 1;
int i;
const unsigned char *z;
int eType;
memset(p, 0, sizeof(*p));
@@ -764,14 +770,7 @@ static int isDate(
}
if( (eType = sqlite3_value_type(argv[0]))==SQLITE_FLOAT
|| eType==SQLITE_INTEGER ){
if( argc>=2 && sqlite3_value_type(argv[1])==SQLITE_TEXT
&& strcmp((const char*)sqlite3_value_text(argv[1]),"unixepoch")==0 ){
i = 2;
p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*1000.0) +
21086676*(i64)10000000;
}else{
p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
}
p->iJD = (sqlite3_int64)(sqlite3_value_double(argv[0])*86400000.0 + 0.5);
p->validJD = 1;
}else{
z = sqlite3_value_text(argv[0]);
@@ -779,8 +778,8 @@ static int isDate(
return 1;
}
}
while( i<argc ){
z = sqlite3_value_text(argv[i++]);
for(i=1; i<argc; i++){
z = sqlite3_value_text(argv[i]);
if( z==0 || parseModifier(context, (char*)z, p) ) return 1;
}
return 0;
@@ -809,27 +808,10 @@ static void juliandayFunc(
}
}
/*
** Render an ISO-8601 year value into the given buffer. Return the
** number of characters.
**
** Years are rendered differently depending on magnitude:
**
** 0..9999 YYYY
** 10000..99999 +YYYYY
** -9999..-1 -YYYY
** -99999..-10000 -YYYYY
*/
static int renderYear(char *zBuf, int Y){
sqlite3_snprintf(10, zBuf, Y<0 ? "%05d" : Y>=10000 ? "%+05d" : "%04d", Y);
return sqlite3Strlen30(zBuf);
}
/*
** datetime( TIMESTRING, MOD, MOD, ...)
**
** Return YYYY-MM-DD HH:MM:SS. The YYYY might be +YYYYY or -YYYY or -YYYYY
** depending on the year.
** Return YYYY-MM-DD HH:MM:SS
*/
static void datetimeFunc(
sqlite3_context *context,
@@ -838,12 +820,10 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
int i;
char zBuf[100];
computeYMD_HMS(&x);
i = renderYear(zBuf, x.Y);
sqlite3_snprintf(sizeof(zBuf)-i, zBuf+i, "-%02d-%02d %02d:%02d:%02d",
x.M, x.D, x.h, x.m, (int)(x.s));
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d",
x.Y, x.M, x.D, x.h, x.m, (int)(x.s));
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
@@ -870,10 +850,7 @@ static void timeFunc(
/*
** date( TIMESTRING, MOD, MOD, ...)
**
** Return YYYY-MM-DD
** or +YYYYY-MM-DD
** or -YYYY-MM-DD
** or -YYYYY-MM-DD
** Return YYYY-MM-DD
*/
static void dateFunc(
sqlite3_context *context,
@@ -882,11 +859,9 @@ static void dateFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
int i;
char zBuf[100];
computeYMD(&x);
i = renderYear(zBuf, x.Y);
sqlite3_snprintf(sizeof(zBuf)-i, zBuf+i, "-%02d-%02d", x.M, x.D);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d", x.Y, x.M, x.D);
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
}
+1
View File
@@ -167,6 +167,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
SQLITE_DEFAULT_WORKER_THREADS, /* nWorker */
/* All the rest should always be initialized to zero */
0, /* isInit */
0, /* inProgress */
+12 -3
View File
@@ -1865,15 +1865,24 @@ static int xferOptimization(
return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
}
for(i=0; i<pDest->nCol; i++){
if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
Column *pDestCol = &pDest->aCol[i];
Column *pSrcCol = &pSrc->aCol[i];
if( pDestCol->affinity!=pSrcCol->affinity ){
return 0; /* Affinity must be the same on all columns */
}
if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
if( !xferCompatibleCollation(pDestCol->zColl, pSrcCol->zColl) ){
return 0; /* Collating sequence must be the same on all columns */
}
if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
if( pDestCol->notNull && !pSrcCol->notNull ){
return 0; /* tab2 must be NOT NULL if tab1 is */
}
/* Default values for second and subsequent columns need to match. */
if( i>0
&& ((pDestCol->zDflt==0)!=(pSrcCol->zDflt==0)
|| (pDestCol->zDflt && strcmp(pDestCol->zDflt, pSrcCol->zDflt)!=0))
){
return 0; /* Default values must be the same for all columns */
}
}
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
if( pDestIdx->onError!=OE_None ){
+15
View File
@@ -515,6 +515,13 @@ int sqlite3_config(int op, ...){
}
#endif
case SQLITE_CONFIG_WORKER_THREADS: {
int n = va_arg(ap, int);
if( n>SQLITE_MAX_WORKER_THREADS ) n = SQLITE_MAX_WORKER_THREADS;
if( n>=0 ) sqlite3GlobalConfig.nWorker = n;
break;
}
default: {
rc = SQLITE_ERROR;
break;
@@ -2497,6 +2504,7 @@ static int openDatabase(
db->nextAutovac = -1;
db->szMmap = sqlite3GlobalConfig.szMmap;
db->nextPagesize = 0;
db->nMaxSorterMmap = 0x7FFFFFFF;
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger | SQLITE_CacheSpill
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
| SQLITE_AutoIndex
@@ -3339,6 +3347,13 @@ int sqlite3_test_control(int op, ...){
break;
}
/* sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, nMax); */
case SQLITE_TESTCTRL_SORTER_MMAP: {
sqlite3 *db = va_arg(ap, sqlite3*);
db->nMaxSorterMmap = va_arg(ap, int);
break;
}
}
va_end(ap);
#endif /* SQLITE_OMIT_BUILTIN_TEST */
+1 -1
View File
@@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){
*/
sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0;
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
#endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
}
+1 -1
View File
@@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
** that means that a mutex could not be allocated.
*/
static sqlite3_mutex *debugMutexAlloc(int id){
static sqlite3_debug_mutex aStatic[6];
static sqlite3_debug_mutex aStatic[8];
sqlite3_debug_mutex *pNew = 0;
switch( id ){
case SQLITE_MUTEX_FAST:
+5 -1
View File
@@ -96,10 +96,12 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
@@ -133,6 +135,8 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER
};
sqlite3_mutex *p;
+6 -2
View File
@@ -93,7 +93,9 @@ static int winMutexNotheld(sqlite3_mutex *p){
/*
** Initialize and deinitialize the mutex subsystem.
*/
static sqlite3_mutex winMutex_staticMutexes[6] = {
static sqlite3_mutex winMutex_staticMutexes[] = {
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
@@ -159,10 +161,12 @@ static int winMutexEnd(void){
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** </ul>
**
** The first two constants cause sqlite3_mutex_alloc() to create
+108 -5
View File
@@ -267,6 +267,7 @@ struct winFile {
sqlite3_int64 mmapSizeActual; /* Actual size of mapped region */
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
#endif
SQLiteThread *preCacheThread; /* Thread used to pre-cache file contents */
};
/*
@@ -948,11 +949,7 @@ static struct win_syscall {
#define osWaitForSingleObject ((DWORD(WINAPI*)(HANDLE, \
DWORD))aSyscall[63].pCurrent)
#if SQLITE_OS_WINRT
{ "WaitForSingleObjectEx", (SYSCALL)WaitForSingleObjectEx, 0 },
#else
{ "WaitForSingleObjectEx", (SYSCALL)0, 0 },
#endif
#define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \
BOOL))aSyscall[64].pCurrent)
@@ -1048,6 +1045,11 @@ static struct win_syscall {
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
{ "DuplicateHandle", (SYSCALL)DuplicateHandle, 0 },
#define osDuplicateHandle ((BOOL(WINAPI*)(HANDLE, \
HANDLE,HANDLE,LPHANDLE,DWORD,BOOL,DWORD))aSyscall[76].pCurrent)
}; /* End of the overrideable system calls */
/*
@@ -1279,6 +1281,13 @@ void sqlite3_win32_sleep(DWORD milliseconds){
#endif
}
DWORD sqlite3Win32Wait(HANDLE hObject){
DWORD rc;
while( (rc = osWaitForSingleObjectEx(hObject, INFINITE,
TRUE))==WAIT_IO_COMPLETION ){}
return rc;
}
/*
** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
** or WinCE. Return false (zero) for Win95, Win98, or WinME.
@@ -2351,6 +2360,13 @@ static int winClose(sqlite3_file *id){
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
OSTRACE(("CLOSE file=%p\n", pFile->h));
#if SQLITE_MAX_WORKER_THREADS>0
if( pFile->preCacheThread ){
void *pOut = 0;
sqlite3ThreadJoin(pFile->preCacheThread, &pOut);
}
#endif
#if SQLITE_MAX_MMAP_SIZE>0
winUnmapfile(pFile);
#endif
@@ -3195,6 +3211,84 @@ static int winDeviceCharacteristics(sqlite3_file *id){
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
}
#if SQLITE_MAX_WORKER_THREADS>0
/*
** Thread routine that attempts to read the entire file. This is used to
** provide a hint to the operating system that the entire file should be held
** in the cache.
*/
static void *winPreCacheThread(void *pCtx){
winFile *pFile = (winFile*)pCtx;
void *pBuf = 0;
DWORD lastErrno;
HANDLE dupHandle = NULL;
DWORD dwSize, dwRet;
DWORD dwAmt;
DWORD nRead;
if( !osDuplicateHandle(GetCurrentProcess(), pFile->h, GetCurrentProcess(),
&dupHandle, 0, FALSE, DUPLICATE_SAME_ACCESS) ){
pFile->lastErrno = osGetLastError();
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR\n", dupHandle));
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR, pFile->lastErrno,
"winPreCacheThread1", pFile->zPath));
}
dwSize = osSetFilePointer(dupHandle, 0, 0, FILE_END);
if( (dwSize==INVALID_SET_FILE_POINTER
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
pFile->lastErrno = lastErrno;
osCloseHandle(dupHandle);
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle));
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
"winPreCacheThread2", pFile->zPath));
}
dwRet = osSetFilePointer(dupHandle, 0, 0, FILE_BEGIN);
if( (dwRet==INVALID_SET_FILE_POINTER
&& ((lastErrno = osGetLastError())!=NO_ERROR)) ){
pFile->lastErrno = lastErrno;
osCloseHandle(dupHandle);
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SEEK\n", dupHandle));
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SEEK, pFile->lastErrno,
"winPreCacheThread3", pFile->zPath));
}
dwAmt = 4194304; /* TODO: Tuning. */
if( dwSize<dwAmt ){
dwAmt = dwSize;
}
pBuf = sqlite3MallocZero( dwAmt );
if( pBuf==0 ){
osCloseHandle(dupHandle);
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_NOMEM\n", dupHandle));
return SQLITE_INT_TO_PTR(SQLITE_IOERR_NOMEM);
}
while( 1 ){
if( !osReadFile(dupHandle, pBuf, dwAmt, &nRead, 0) ){
pFile->lastErrno = osGetLastError();
sqlite3_free(pBuf);
osCloseHandle(dupHandle);
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_READ\n", dupHandle));
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_READ, pFile->lastErrno,
"winPreCacheThread4", pFile->zPath));
}
if( nRead<dwAmt ){
sqlite3_free(pBuf);
osCloseHandle(dupHandle);
OSTRACE(("PRE-CACHE file=%p, rc=SQLITE_IOERR_SHORT_READ\n", dupHandle));
return SQLITE_INT_TO_PTR(winLogError(SQLITE_IOERR_SHORT_READ,
pFile->lastErrno,
"winPreCacheThread5", pFile->zPath));
}
dwSize -= dwAmt;
if( dwSize==0 ){
break;
}
}
sqlite3_free(pBuf);
osCloseHandle(dupHandle);
return SQLITE_INT_TO_PTR(SQLITE_OK);
}
#endif
/*
** Windows will only let you create file view mappings
** on allocation size granularity boundaries.
@@ -4701,6 +4795,15 @@ static int winOpen(
pFile->mmapSizeActual = 0;
pFile->mmapSizeMax = sqlite3GlobalConfig.szMmap;
#endif
#if SQLITE_MAX_WORKER_THREADS>0
sqlite3ThreadCreate(&pFile->preCacheThread, winPreCacheThread, pFile);
{
void *pOut = 0;
sqlite3ThreadJoin(pFile->preCacheThread, &pOut);
pFile->preCacheThread = 0;
}
#endif
OpenCounter(+1);
return rc;
@@ -5419,7 +5522,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==76 );
assert( ArraySize(aSyscall)==77 );
/* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
+4 -2
View File
@@ -1488,13 +1488,15 @@ void sqlite3Pragma(
sqlite3VdbeAddOp2(v, OP_Null, 0, 2);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pTab->szTabRow), 3);
sqlite3VdbeAddOp2(v, OP_Integer, (int)pTab->nRowEst, 4);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pTab->nRowLogEst), 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pIdx->szIdxRow), 3);
sqlite3VdbeAddOp2(v, OP_Integer, (int)pIdx->aiRowEst[0], 4);
sqlite3VdbeAddOp2(v, OP_Integer,
(int)sqlite3LogEstToInt(pIdx->aiRowLogEst[0]), 4);
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
}
}
+95 -68
View File
@@ -455,26 +455,43 @@ static KeyInfo *keyInfoFromExprList(
);
/*
** Insert code into "v" that will push the record in register regData
** into the sorter.
** Generate code that will push the record in registers regData
** through regData+nData-1 onto the sorter.
*/
static void pushOntoSorter(
Parse *pParse, /* Parser context */
SortCtx *pSort, /* Information about the ORDER BY clause */
Select *pSelect, /* The whole SELECT statement */
int regData /* Register holding data to be sorted */
int regData, /* First register holding data to be sorted */
int nData, /* Number of elements in the data array */
int nPrefixReg /* No. of reg prior to regData available for use */
){
Vdbe *v = pParse->pVdbe;
int nExpr = pSort->pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
int nOBSat = pSort->nOBSat;
int op;
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nExpr+2-nOBSat, regRecord);
Vdbe *v = pParse->pVdbe; /* Stmt under construction */
int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0);
int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */
int nBase = nExpr + bSeq + nData; /* Fields in sorter record */
int regBase; /* Regs for sorter record */
int regRecord = ++pParse->nMem; /* Assembled sorter record */
int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */
int op; /* Opcode to add sorter record to sorter */
assert( bSeq==0 || bSeq==1 );
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nExpr - bSeq;
}else{
regBase = pParse->nMem + 1;
pParse->nMem += nBase;
}
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, SQLITE_ECEL_DUP);
if( bSeq ){
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
}
if( nPrefixReg==0 ){
sqlite3VdbeAddOp3(v, OP_Move, regData, regBase+nExpr+bSeq, nData);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
if( nOBSat>0 ){
int regPrevKey; /* The first nOBSat columns of the previous row */
int addrFirst; /* Address of the OP_IfNot opcode */
@@ -485,12 +502,17 @@ static void pushOntoSorter(
regPrevKey = pParse->nMem+1;
pParse->nMem += pSort->nOBSat;
nKey = nExpr - pSort->nOBSat + 1;
addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr); VdbeCoverage(v);
nKey = nExpr - pSort->nOBSat + bSeq;
if( bSeq ){
addrFirst = sqlite3VdbeAddOp1(v, OP_IfNot, regBase+nExpr);
}else{
addrFirst = sqlite3VdbeAddOp1(v, OP_SequenceTest, pSort->iECursor);
}
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_Compare, regPrevKey, regBase, pSort->nOBSat);
pOp = sqlite3VdbeGetOp(v, pSort->addrSortIndex);
if( pParse->db->mallocFailed ) return;
pOp->p2 = nKey + 1;
pOp->p2 = nKey + nData;
pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
@@ -511,10 +533,6 @@ static void pushOntoSorter(
op = OP_IdxInsert;
}
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( nOBSat==0 ){
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
}
if( pSelect->iLimit ){
int addr1, addr2;
int iLimit;
@@ -629,6 +647,7 @@ static void selectInnerLoop(
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
int nPrefixReg = 0; /* Number of extra registers before regResult */
assert( v );
assert( pEList!=0 );
@@ -644,6 +663,11 @@ static void selectInnerLoop(
nResultCol = pEList->nExpr;
if( pDest->iSdst==0 ){
if( pSort ){
nPrefixReg = pSort->pOrderBy->nExpr;
if( !(pSort->sortFlags & SORTFLAG_UseSorter) ) nPrefixReg++;
pParse->nMem += nPrefixReg;
}
pDest->iSdst = pParse->nMem+1;
pParse->nMem += nResultCol;
}else if( pDest->iSdst+nResultCol > pParse->nMem ){
@@ -760,10 +784,10 @@ static void selectInnerLoop(
case SRT_DistFifo:
case SRT_Table:
case SRT_EphemTab: {
int r1 = sqlite3GetTempReg(pParse);
int r1 = sqlite3GetTempRange(pParse, nPrefixReg+1);
testcase( eDest==SRT_Table );
testcase( eDest==SRT_EphemTab );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -778,7 +802,7 @@ static void selectInnerLoop(
}
#endif
if( pSort ){
pushOntoSorter(pParse, pSort, p, r1);
pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -786,7 +810,7 @@ static void selectInnerLoop(
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
break;
}
@@ -804,7 +828,7 @@ static void selectInnerLoop(
** ORDER BY in this case since the order of entries in the set
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
pushOntoSorter(pParse, pSort, p, regResult);
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
@@ -830,7 +854,7 @@ static void selectInnerLoop(
case SRT_Mem: {
assert( nResultCol==1 );
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult);
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
/* The LIMIT clause will jump out of the loop for us */
@@ -844,10 +868,7 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
pushOntoSorter(pParse, pSort, p, r1);
sqlite3ReleaseTempReg(pParse, r1);
pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
@@ -1127,46 +1148,62 @@ static void generateSortTail(
int addr;
int addrOnce = 0;
int iTab;
int pseudoTab = 0;
ExprList *pOrderBy = pSort->pOrderBy;
int eDest = pDest->eDest;
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
int nKey;
int iSortTab; /* Sorter cursor to read from */
int nSortData; /* Trailing values to read from sorter */
u8 p5; /* p5 parameter for 1st OP_Column */
int i;
int bSeq; /* True if sorter record includes seq. no. */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
struct ExprList_item *aOutEx = p->pEList->a;
#endif
if( pSort->labelBkOut ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
iTab = pSort->iECursor;
regRow = sqlite3GetTempReg(pParse);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
pseudoTab = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, pseudoTab, regRow, nColumn);
regRowid = 0;
regRow = pDest->iSdst;
nSortData = nColumn;
}else{
regRowid = sqlite3GetTempReg(pParse);
regRow = sqlite3GetTempReg(pParse);
nSortData = 1;
}
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
int ptab2 = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, nKey+2);
iSortTab = pParse->nTab++;
if( pSort->labelBkOut ){
addrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v);
}
sqlite3VdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut, nKey+1+nSortData);
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp2(v, OP_SorterData, iTab, regSortOut);
sqlite3VdbeAddOp3(v, OP_Column, ptab2, nKey+1, regRow);
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
p5 = OPFLAG_CLEARCACHE;
bSeq = 0;
}else{
if( addrOnce ) sqlite3VdbeJumpHere(v, addrOnce);
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp3(v, OP_Column, iTab, nKey+1, regRow);
iSortTab = iTab;
p5 = 0;
bSeq = 1;
}
for(i=0; i<nSortData; i++){
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
if( i==0 ) sqlite3VdbeChangeP5(v, p5);
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
}
switch( eDest ){
case SRT_Table:
@@ -1195,17 +1232,9 @@ static void generateSortTail(
}
#endif
default: {
int i;
assert( eDest==SRT_Output || eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
testcase( eDest==SRT_Coroutine );
for(i=0; i<nColumn; i++){
assert( regRow!=pDest->iSdst+i );
sqlite3VdbeAddOp3(v, OP_Column, pseudoTab, i, pDest->iSdst+i);
if( i==0 ){
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
}
}
if( eDest==SRT_Output ){
sqlite3VdbeAddOp2(v, OP_ResultRow, pDest->iSdst, nColumn);
sqlite3ExprCacheAffinityChange(pParse, pDest->iSdst, nColumn);
@@ -1215,9 +1244,10 @@ static void generateSortTail(
break;
}
}
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
if( regRowid ){
sqlite3ReleaseTempReg(pParse, regRow);
sqlite3ReleaseTempReg(pParse, regRowid);
}
/* The bottom of the loop
*/
sqlite3VdbeResolveLabel(v, addrContinue);
@@ -1228,9 +1258,6 @@ static void generateSortTail(
}
if( pSort->regReturn ) sqlite3VdbeAddOp1(v, OP_Return, pSort->regReturn);
sqlite3VdbeResolveLabel(v, addrBreak);
if( eDest==SRT_Output || eDest==SRT_Coroutine ){
sqlite3VdbeAddOp2(v, OP_Close, pseudoTab, 0);
}
}
/*
@@ -1690,7 +1717,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
assert( db->lookaside.bEnabled==0 );
pTab->nRef = 1;
pTab->zName = 0;
pTab->nRowEst = 1048576;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
selectAddColumnTypeAndCollation(pParse, pTab, pSelect);
pTab->iPKey = -1;
@@ -3829,7 +3856,7 @@ static int withExpand(
pTab->nRef = 1;
pTab->zName = sqlite3DbStrDup(db, pCte->zName);
pTab->iPKey = -1;
pTab->nRowEst = 1048576;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral;
pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0);
if( db->mallocFailed ) return SQLITE_NOMEM;
@@ -4005,7 +4032,7 @@ static int selectExpander(Walker *pWalker, Select *p){
while( pSel->pPrior ){ pSel = pSel->pPrior; }
selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
pTab->iPKey = -1;
pTab->nRowEst = 1048576;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
pTab->tabFlags |= TF_Ephemeral;
#endif
}else{
@@ -4655,7 +4682,7 @@ int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
pItem->viaCoroutine = 1;
pItem->regResult = dest.iSdst;
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
@@ -4686,7 +4713,7 @@ int sqlite3Select(
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow);
if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr);
retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn);
VdbeComment((v, "end %s", pItem->pTab->zName));
@@ -4760,8 +4787,9 @@ int sqlite3Select(
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
sSort.iECursor, sSort.pOrderBy->nExpr+2, 0,
(char*)pKeyInfo, P4_KEYINFO);
sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
(char*)pKeyInfo, P4_KEYINFO
);
}else{
sSort.addrSortIndex = -1;
}
@@ -4892,7 +4920,7 @@ int sqlite3Select(
sNC.pSrcList = pTabList;
sNC.pAggInfo = &sAggInfo;
sAggInfo.mnReg = pParse->nMem+1;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr+1 : 0;
sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
sAggInfo.pGroupBy = pGroupBy;
sqlite3ExprAnalyzeAggList(&sNC, pEList);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
@@ -4985,8 +5013,8 @@ int sqlite3Select(
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
nCol = nGroupBy + 1;
j = nGroupBy+1;
nCol = nGroupBy;
j = nGroupBy;
for(i=0; i<sAggInfo.nColumn; i++){
if( sAggInfo.aCol[i].iSorterColumn>=j ){
nCol++;
@@ -4996,8 +5024,7 @@ int sqlite3Select(
regBase = sqlite3GetTempRange(pParse, nCol);
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
j = nGroupBy+1;
j = nGroupBy;
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn>=j ){
+2 -1
View File
@@ -3536,7 +3536,8 @@ static void main_init(struct callback_data *data) {
sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> ");
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, 4);
}
/*
+19 -3
View File
@@ -1715,6 +1715,16 @@ struct sqlite3_mem_methods {
** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
** </dl>
**
** [[SQLITE_CONFIG_WORKER_THREADS]]
** <dt>SQLITE_CONFIG_WORKER_THREADS
** <dd>^SQLITE_CONFIG_WORKER_THREADS takes a single argument of type int.
** It is used to set the number of background worker threads that may be
** launched when sorting large amounts of data. A value of 0 means launch
** no background threads at all. The maximum number of background threads
** allowed is configured at build-time by the SQLITE_MAX_WORKER_THREADS
** pre-processor option.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
@@ -1739,6 +1749,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_WORKER_THREADS 24 /* int nWorker */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -5817,10 +5828,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2
** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_LRU2
** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** </ul>)^
**
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
@@ -6024,6 +6037,8 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
/*
** CAPI3REF: Retrieve the mutex for a database connection
@@ -6119,7 +6134,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_LAST 22
#define SQLITE_TESTCTRL_SORTER_MMAP 23
#define SQLITE_TESTCTRL_LAST 23
/*
** CAPI3REF: SQLite Runtime Status
+43 -5
View File
@@ -422,6 +422,26 @@
# define SQLITE_TEMP_STORE_xc 1 /* Exclude from ctime.c */
#endif
/*
** If no value has been provided for SQLITE_MAX_WORKER_THREADS, or if
** SQLITE_TEMP_STORE is set to 3 (never use temporary files), set it
** to zero.
*/
#if SQLITE_TEMP_STORE==3
# undef SQLITE_MAX_WORKER_THREADS
#endif
#ifndef SQLITE_MAX_WORKER_THREADS
# define SQLITE_MAX_WORKER_THREADS 0
#endif
#ifndef SQLITE_DEFAULT_WORKER_THREADS
# define SQLITE_DEFAULT_WORKER_THREADS 0
#endif
#if SQLITE_DEFAULT_WORKER_THREADS>SQLITE_MAX_WORKER_THREADS
# undef SQLITE_MAX_WORKER_THREADS
# define SQLITE_MAX_WORKER_THREADS SQLITE_DEFAULT_WORKER_THREADS
#endif
/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
@@ -525,10 +545,10 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
** gives a possible range of values of approximately 1.0e986 to 1e-986.
** But the allowed values are "grainy". Not every value is representable.
** For example, quantities 16 and 17 are both represented by a LogEst
** of 40. However, since LogEst quantatites are suppose to be estimates,
** of 40. However, since LogEst quantaties are suppose to be estimates,
** not exact values, this imprecision is not a problem.
**
** "LogEst" is short for "Logarithimic Estimate".
** "LogEst" is short for "Logarithmic Estimate".
**
** Examples:
** 1 -> 0 20 -> 43 10000 -> 132
@@ -805,6 +825,7 @@ typedef struct PrintfArguments PrintfArguments;
typedef struct RowSet RowSet;
typedef struct Savepoint Savepoint;
typedef struct Select Select;
typedef struct SQLiteThread SQLiteThread;
typedef struct SelectDest SelectDest;
typedef struct SrcList SrcList;
typedef struct StrAccum StrAccum;
@@ -984,6 +1005,7 @@ struct sqlite3 {
int nChange; /* Value returned by sqlite3_changes() */
int nTotalChange; /* Value returned by sqlite3_total_changes() */
int aLimit[SQLITE_N_LIMIT]; /* Limits */
int nMaxSorterMmap; /* Maximum size of regions mapped by sorter */
struct sqlite3InitInfo { /* Information used during initialization */
int newTnum; /* Rootpage of table being initialized */
u8 iDb; /* Which db file is being initialized */
@@ -1471,7 +1493,7 @@ struct Table {
#ifndef SQLITE_OMIT_CHECK
ExprList *pCheck; /* All CHECK constraints */
#endif
tRowcnt nRowEst; /* Estimated rows in table - from sqlite_stat1 table */
LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */
int tnum; /* Root BTree node for this table (see note above) */
i16 iPKey; /* If not negative, use aCol[iPKey] as the primary key */
i16 nCol; /* Number of columns in this table */
@@ -1644,7 +1666,7 @@ struct UnpackedRecord {
KeyInfo *pKeyInfo; /* Collation and sort-order information */
u16 nField; /* Number of entries in apMem[] */
i8 default_rc; /* Comparison result if keys are equal */
u8 isCorrupt; /* Corruption detected by xRecordCompare() */
u8 errCode; /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
Mem *aMem; /* Values */
int r1; /* Value to return if (lhs > rhs) */
int r2; /* Value to return if (rhs < lhs) */
@@ -1680,7 +1702,7 @@ struct UnpackedRecord {
struct Index {
char *zName; /* Name of this index */
i16 *aiColumn; /* Which columns are used by this index. 1st is 0 */
tRowcnt *aiRowEst; /* From ANALYZE: Est. rows selected by each column */
LogEst *aiRowLogEst; /* From ANALYZE: Est. rows selected by each column */
Table *pTable; /* The SQL table being indexed */
char *zColAff; /* String defining the affinity of each column */
Index *pNext; /* The next index associated with the same table */
@@ -2702,6 +2724,7 @@ struct Sqlite3Config {
int nPage; /* Number of pages in pPage[] */
int mxParserStack; /* maximum depth of the parser stack */
int sharedCacheEnabled; /* true if shared-cache mode enabled */
int nWorker; /* Number of worker threads to use */
/* The above might be initialized to non-zero. The following need to always
** initially be zero, however. */
int isInit; /* True after initialization has finished */
@@ -3653,4 +3676,19 @@ SQLITE_EXTERN void (*sqlite3IoTrace)(const char*,...);
#define MEMTYPE_PCACHE 0x08 /* Page cache allocations */
#define MEMTYPE_DB 0x10 /* Uses sqlite3DbMalloc, not sqlite_malloc */
/*
** Threading interface
*/
#if SQLITE_MAX_WORKER_THREADS>0
int sqlite3ThreadCreate(SQLiteThread**,void*(*)(void*),void*);
int sqlite3ThreadJoin(SQLiteThread*, void**);
#endif
/*
** Win32 interface
*/
#if SQLITE_OS_WIN
DWORD sqlite3Win32Wait(HANDLE hObject);
#endif
#endif /* _SQLITEINT_H_ */
+164
View File
@@ -2703,6 +2703,46 @@ bad_args:
return TCL_ERROR;
}
/*
** Usage: add_test_utf16bin_collate <db ptr>
**
** Add a utf-16 collation sequence named "utf16bin" to the database
** handle. This collation sequence compares arguments in the same way as the
** built-in collation "binary".
*/
static int test_utf16bin_collate_func(
void *pCtx,
int nA, const void *zA,
int nB, const void *zB
){
int nCmp = (nA>nB ? nB : nA);
int res = memcmp(zA, zB, nCmp);
if( res==0 ) res = nA - nB;
return res;
}
static int test_utf16bin_collate(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int rc;
if( objc!=2 ) goto bad_args;
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0,
test_utf16bin_collate_func
);
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
bad_args:
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
/*
** When the collation needed callback is invoked, record the name of
** the requested collating function here. The recorded name is linked
@@ -5844,6 +5884,7 @@ static int test_test_control(
int i;
} aVerb[] = {
{ "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
{ "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP },
};
int iVerb;
int iFlag;
@@ -5871,6 +5912,19 @@ static int test_test_control(
sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
break;
}
case SQLITE_TESTCTRL_SORTER_MMAP: {
int val;
sqlite3 *db;
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
break;
}
}
Tcl_ResetResult(interp);
@@ -6282,6 +6336,113 @@ static int tclLoadStaticExtensionCmd(
return TCL_OK;
}
/*
** sorter_test_fakeheap BOOL
**
*/
static int sorter_test_fakeheap(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int bArg;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
return TCL_ERROR;
}
if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){
return TCL_ERROR;
}
if( bArg ){
if( sqlite3GlobalConfig.pHeap==0 ){
sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1);
}
}else{
if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){
sqlite3GlobalConfig.pHeap = 0;
}
}
Tcl_ResetResult(interp);
return TCL_OK;
}
/*
** sorter_test_sort4_helper DB SQL1 NSTEP SQL2
**
** Compile SQL statement $SQL1 and step it $NSTEP times. For each row,
** check that the leftmost and rightmost columns returned are both integers,
** and that both contain the same value.
**
** Then execute statement $SQL2. Check that the statement returns the same
** set of integers in the same order as in the previous step (using $SQL1).
*/
static int sorter_test_sort4_helper(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
const char *zSql1;
const char *zSql2;
int nStep;
int iStep;
int iCksum1 = 0;
int iCksum2 = 0;
int rc;
int iB;
sqlite3 *db;
sqlite3_stmt *pStmt;
if( objc!=5 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
zSql1 = Tcl_GetString(objv[2]);
if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR;
zSql2 = Tcl_GetString(objv[4]);
rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
if( rc!=SQLITE_OK ) goto sql_error;
iB = sqlite3_column_count(pStmt)-1;
for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
int a = sqlite3_column_int(pStmt, 0);
if( a!=sqlite3_column_int(pStmt, iB) ){
Tcl_AppendResult(interp, "data error: (a!=b)", 0);
return TCL_ERROR;
}
iCksum1 += (iCksum1 << 3) + a;
}
rc = sqlite3_finalize(pStmt);
if( rc!=SQLITE_OK ) goto sql_error;
rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
if( rc!=SQLITE_OK ) goto sql_error;
for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
int a = sqlite3_column_int(pStmt, 0);
iCksum2 += (iCksum2 << 3) + a;
}
rc = sqlite3_finalize(pStmt);
if( rc!=SQLITE_OK ) goto sql_error;
if( iCksum1!=iCksum2 ){
Tcl_AppendResult(interp, "checksum mismatch", 0);
return TCL_ERROR;
}
return TCL_OK;
sql_error:
Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
/*
** Register commands with the TCL interpreter.
@@ -6481,6 +6642,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "add_test_collate", test_collate, 0 },
{ "add_test_collate_needed", test_collate_needed, 0 },
{ "add_test_function", test_function, 0 },
{ "add_test_utf16bin_collate", test_utf16bin_collate, 0 },
#endif
{ "sqlite3_test_errstr", test_errstr, 0 },
{ "tcl_variable_type", tcl_variable_type, 0 },
@@ -6514,6 +6676,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "getrusage", test_getrusage },
#endif
{ "load_static_extension", tclLoadStaticExtensionCmd },
{ "sorter_test_fakeheap", sorter_test_fakeheap },
{ "sorter_test_sort4_helper", sorter_test_sort4_helper },
};
static int bitmask_size = sizeof(Bitmask)*8;
int i;
+4
View File
@@ -99,6 +99,10 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY);
#endif
Tcl_SetVar2(interp, "sqlite_options", "worker_threads",
STRINGVALUE(SQLITE_MAX_WORKER_THREADS), TCL_GLOBAL_ONLY
);
#if 1 /* def SQLITE_MEMDEBUG */
Tcl_SetVar2(interp, "sqlite_options", "memdebug", "1", TCL_GLOBAL_ONLY);
#else
+27
View File
@@ -1253,6 +1253,32 @@ static int test_config_cis(
return TCL_OK;
}
/*
** Usage: sqlite3_config_worker_threads N
*/
static int test_config_worker_threads(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int rc;
int nThread;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "N");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &nThread) ){
return TCL_ERROR;
}
rc = sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, nThread);
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
return TCL_OK;
}
/*
** Usage: sqlite3_dump_memsys3 FILENAME
** sqlite3_dump_memsys5 FILENAME
@@ -1506,6 +1532,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_config_error", test_config_error ,0 },
{ "sqlite3_config_uri", test_config_uri ,0 },
{ "sqlite3_config_cis", test_config_cis ,0 },
{ "sqlite3_config_worker_threads", test_config_worker_threads ,0 },
{ "sqlite3_db_config_lookaside",test_db_config_lookaside ,0 },
{ "sqlite3_dump_memsys3", test_dump_memsys3 ,3 },
{ "sqlite3_dump_memsys5", test_dump_memsys3 ,5 },
+183 -17
View File
@@ -35,6 +35,8 @@ struct Circle {
double centerx;
double centery;
double radius;
double mxArea;
int eScoreType;
};
/*
@@ -50,11 +52,7 @@ static void circle_del(void *p){
static int circle_geom(
sqlite3_rtree_geometry *p,
int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord,
#endif
sqlite3_rtree_dbl *aCoord,
int *pRes
){
int i; /* Iterator variable */
@@ -62,7 +60,12 @@ static int circle_geom(
double xmin, xmax; /* X dimensions of box being tested */
double ymin, ymax; /* X dimensions of box being tested */
if( p->pUser==0 ){
xmin = aCoord[0];
xmax = aCoord[1];
ymin = aCoord[2];
ymax = aCoord[3];
pCircle = (Circle *)p->pUser;
if( pCircle==0 ){
/* If pUser is still 0, then the parameter values have not been tested
** for correctness or stored into a Circle structure yet. Do this now. */
@@ -108,14 +111,9 @@ static int circle_geom(
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
pCircle->aBox[1].ymin = pCircle->centery;
pCircle->aBox[1].ymax = pCircle->centery;
pCircle->mxArea = (xmax - xmin)*(ymax - ymin) + 1.0;
}
pCircle = (Circle *)p->pUser;
xmin = aCoord[0];
xmax = aCoord[1];
ymin = aCoord[2];
ymax = aCoord[3];
/* Check if any of the 4 corners of the bounding-box being tested lie
** inside the circular region. If they do, then the bounding-box does
** intersect the region of interest. Set the output variable to true and
@@ -154,6 +152,170 @@ static int circle_geom(
return SQLITE_OK;
}
/*
** Implementation of "circle" r-tree geometry callback using the
** 2nd-generation interface that allows scoring.
*/
static int circle_query_func(sqlite3_rtree_query_info *p){
int i; /* Iterator variable */
Circle *pCircle; /* Structure defining circular region */
double xmin, xmax; /* X dimensions of box being tested */
double ymin, ymax; /* X dimensions of box being tested */
int nWithin = 0; /* Number of corners inside the circle */
xmin = p->aCoord[0];
xmax = p->aCoord[1];
ymin = p->aCoord[2];
ymax = p->aCoord[3];
pCircle = (Circle *)p->pUser;
if( pCircle==0 ){
/* If pUser is still 0, then the parameter values have not been tested
** for correctness or stored into a Circle structure yet. Do this now. */
/* This geometry callback is for use with a 2-dimensional r-tree table.
** Return an error if the table does not have exactly 2 dimensions. */
if( p->nCoord!=4 ) return SQLITE_ERROR;
/* Test that the correct number of parameters (4) have been supplied,
** and that the parameters are in range (that the radius of the circle
** radius is greater than zero). */
if( p->nParam!=4 || p->aParam[2]<0.0 ) return SQLITE_ERROR;
/* Allocate a structure to cache parameter data in. Return SQLITE_NOMEM
** if the allocation fails. */
pCircle = (Circle *)(p->pUser = sqlite3_malloc(sizeof(Circle)));
if( !pCircle ) return SQLITE_NOMEM;
p->xDelUser = circle_del;
/* Record the center and radius of the circular region. One way that
** tested bounding boxes that intersect the circular region are detected
** is by testing if each corner of the bounding box lies within radius
** units of the center of the circle. */
pCircle->centerx = p->aParam[0];
pCircle->centery = p->aParam[1];
pCircle->radius = p->aParam[2];
pCircle->eScoreType = (int)p->aParam[3];
/* Define two bounding box regions. The first, aBox[0], extends to
** infinity in the X dimension. It covers the same range of the Y dimension
** as the circular region. The second, aBox[1], extends to infinity in
** the Y dimension and is constrained to the range of the circle in the
** X dimension.
**
** Then imagine each box is split in half along its short axis by a line
** that intersects the center of the circular region. A bounding box
** being tested can be said to intersect the circular region if it contains
** points from each half of either of the two infinite bounding boxes.
*/
pCircle->aBox[0].xmin = pCircle->centerx;
pCircle->aBox[0].xmax = pCircle->centerx;
pCircle->aBox[0].ymin = pCircle->centery + pCircle->radius;
pCircle->aBox[0].ymax = pCircle->centery - pCircle->radius;
pCircle->aBox[1].xmin = pCircle->centerx + pCircle->radius;
pCircle->aBox[1].xmax = pCircle->centerx - pCircle->radius;
pCircle->aBox[1].ymin = pCircle->centery;
pCircle->aBox[1].ymax = pCircle->centery;
pCircle->mxArea = 200.0*200.0;
}
/* Check if any of the 4 corners of the bounding-box being tested lie
** inside the circular region. If they do, then the bounding-box does
** intersect the region of interest. Set the output variable to true and
** return SQLITE_OK in this case. */
for(i=0; i<4; i++){
double x = (i&0x01) ? xmax : xmin;
double y = (i&0x02) ? ymax : ymin;
double d2;
d2 = (x-pCircle->centerx)*(x-pCircle->centerx);
d2 += (y-pCircle->centery)*(y-pCircle->centery);
if( d2<(pCircle->radius*pCircle->radius) ) nWithin++;
}
/* Check if the bounding box covers any other part of the circular region.
** See comments above for a description of how this test works. If it does
** cover part of the circular region, set the output variable to true
** and return SQLITE_OK. */
if( nWithin==0 ){
for(i=0; i<2; i++){
if( xmin<=pCircle->aBox[i].xmin
&& xmax>=pCircle->aBox[i].xmax
&& ymin<=pCircle->aBox[i].ymin
&& ymax>=pCircle->aBox[i].ymax
){
nWithin = 1;
break;
}
}
}
if( pCircle->eScoreType==1 ){
/* Depth first search */
p->rScore = p->iLevel;
}else if( pCircle->eScoreType==2 ){
/* Breadth first search */
p->rScore = 100 - p->iLevel;
}else if( pCircle->eScoreType==3 ){
/* Depth-first search, except sort the leaf nodes by area with
** the largest area first */
if( p->iLevel==1 ){
p->rScore = 1.0 - (xmax-xmin)*(ymax-ymin)/pCircle->mxArea;
if( p->rScore<0.01 ) p->rScore = 0.01;
}else{
p->rScore = 0.0;
}
}else if( pCircle->eScoreType==4 ){
/* Depth-first search, except exclude odd rowids */
p->rScore = p->iLevel;
if( p->iRowid&1 ) nWithin = 0;
}else{
/* Breadth-first search, except exclude odd rowids */
p->rScore = 100 - p->iLevel;
if( p->iRowid&1 ) nWithin = 0;
}
if( nWithin==0 ){
p->eWithin = NOT_WITHIN;
}else if( nWithin>=4 ){
p->eWithin = FULLY_WITHIN;
}else{
p->eWithin = PARTLY_WITHIN;
}
return SQLITE_OK;
}
/*
** Implementation of "breadthfirstsearch" r-tree geometry callback using the
** 2nd-generation interface that allows scoring.
**
** ... WHERE id MATCH breadthfirstsearch($x0,$x1,$y0,$y1) ...
**
** It returns all entries whose bounding boxes overlap with $x0,$x1,$y0,$y1.
*/
static int bfs_query_func(sqlite3_rtree_query_info *p){
double x0,x1,y0,y1; /* Dimensions of box being tested */
double bx0,bx1,by0,by1; /* Boundary of the query function */
if( p->nParam!=4 ) return SQLITE_ERROR;
x0 = p->aCoord[0];
x1 = p->aCoord[1];
y0 = p->aCoord[2];
y1 = p->aCoord[3];
bx0 = p->aParam[0];
bx1 = p->aParam[1];
by0 = p->aParam[2];
by1 = p->aParam[3];
p->rScore = 100 - p->iLevel;
if( p->eParentWithin==FULLY_WITHIN ){
p->eWithin = FULLY_WITHIN;
}else if( x0>=bx0 && x1<=bx1 && y0>=by0 && y1<=by1 ){
p->eWithin = FULLY_WITHIN;
}else if( x1>=bx0 && x0<=bx1 && y1>=by0 && y0<=by1 ){
p->eWithin = PARTLY_WITHIN;
}else{
p->eWithin = NOT_WITHIN;
}
return SQLITE_OK;
}
/* END of implementation of "circle" geometry callback.
**************************************************************************
*************************************************************************/
@@ -194,11 +356,7 @@ static int gHere = 42;
static int cube_geom(
sqlite3_rtree_geometry *p,
int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord,
#endif
sqlite3_rtree_dbl *aCoord,
int *piRes
){
Cube *pCube = (Cube *)p->pUser;
@@ -293,6 +451,14 @@ static int register_circle_geom(
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_rtree_geometry_callback(db, "circle", circle_geom, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_rtree_query_callback(db, "Qcircle",
circle_query_func, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_rtree_query_callback(db, "breadthfirstsearch",
bfs_query_func, 0, 0);
}
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
#endif
return TCL_OK;
+1 -1
View File
@@ -678,7 +678,7 @@ static int vfstraceAccess(
vfstrace_info *pInfo = (vfstrace_info*)pVfs->pAppData;
sqlite3_vfs *pRoot = pInfo->pRootVfs;
int rc;
vfstrace_printf(pInfo, "%s.xDelete(\"%s\",%d)",
vfstrace_printf(pInfo, "%s.xAccess(\"%s\",%d)",
pInfo->zVfsName, zPath, flags);
rc = pRoot->xAccess(pRoot, zPath, flags, pResOut);
vfstrace_print_errcode(pInfo, " -> %s", rc);
+234
View File
@@ -0,0 +1,234 @@
/*
** 2012 July 21
**
** 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 presents a simple cross-platform threading interface for
** use internally by SQLite.
**
** A "thread" can be created using sqlite3ThreadCreate(). This thread
** runs independently of its creator until it is joined using
** sqlite3ThreadJoin(), at which point it terminates.
**
** Threads do not have to be real. It could be that the work of the
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
** or sqlite3ThreadJoin() call. This is, in fact, what happens in
** single threaded systems. Nothing in SQLite requires multiple threads.
** This interface exists so that applications that want to take advantage
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/
#include "sqliteInt.h"
#if SQLITE_MAX_WORKER_THREADS>0
/********************************* Unix Pthreads ****************************/
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <pthread.h>
/* A running thread */
struct SQLiteThread {
pthread_t tid; /* Thread ID */
int done; /* Set to true when thread finishes */
void *pOut; /* Result returned by the thread */
void *(*xTask)(void*); /* The thread routine */
void *pIn; /* Argument to the thread */
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
memset(p, 0, sizeof(*p));
p->xTask = xTask;
p->pIn = pIn;
if( sqlite3GlobalConfig.bCoreMutex==0
|| pthread_create(&p->tid, 0, xTask, pIn)!=0
){
p->done = 1;
p->pOut = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
int rc;
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->done ){
*ppOut = p->pOut;
rc = SQLITE_OK;
}else{
rc = pthread_join(p->tid, ppOut);
}
sqlite3_free(p);
return rc ? SQLITE_ERROR : SQLITE_OK;
}
#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
/******************************** End Unix Pthreads *************************/
/********************************* Win32 Threads ****************************/
#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <process.h>
/* A running thread */
struct SQLiteThread {
uintptr_t tid; /* The thread handle */
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Thread procedure Win32 compatibility shim */
static void sqlite3ThreadProc(
void *pArg /* IN: Pointer to the SQLiteThread structure */
){
SQLiteThread *p = (SQLiteThread *)pArg;
assert( p!=0 );
assert( p->xTask!=0 );
p->pResult = p->xTask(p->pIn);
_endthread();
}
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
if( sqlite3GlobalConfig.bCoreMutex==0 ){
memset(p, 0, sizeof(*p));
}else{
p->xTask = xTask;
p->pIn = pIn;
p->tid = _beginthread(sqlite3ThreadProc, 0, p);
if( p->tid==(uintptr_t)-1 ){
memset(p, 0, sizeof(*p));
}
}
if( p->xTask==0 ){
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
DWORD rc;
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->xTask==0 ){
rc = WAIT_OBJECT_0;
}else{
rc = sqlite3Win32Wait((HANDLE)p->tid);
assert( rc!=WAIT_IO_COMPLETION );
}
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
sqlite3_free(p);
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}
#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
/******************************** End Win32 Threads *************************/
/********************************* Single-Threaded **************************/
#ifndef SQLITE_THREADS_IMPLEMENTED
/*
** This implementation does not actually create a new thread. It does the
** work of the thread in the main thread, when either the thread is created
** or when it is joined
*/
/* A running thread */
struct SQLiteThread {
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM;
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
p->xTask = xTask;
p->pIn = pIn;
}else{
p->xTask = 0;
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
assert( ppOut!=0 );
if( p==0 ) return SQLITE_NOMEM;
if( p->xTask ){
*ppOut = p->xTask(p->pIn);
}else{
*ppOut = p->pResult;
}
sqlite3_free(p);
#if defined(SQLITE_TEST)
{
void *pTstAlloc = sqlite3Malloc(10);
if (!pTstAlloc) return SQLITE_NOMEM;
sqlite3_free(pTstAlloc);
}
#endif
return SQLITE_OK;
}
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
/****************************** End Single-Threaded *************************/
#endif /* SQLITE_MAX_WORKER_THREADS>0 */
+2 -2
View File
@@ -1246,8 +1246,8 @@ LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
}
/*
** Convert an integer into a LogEst. In other words, compute a
** good approximatation for 10*log2(x).
** Convert an integer into a LogEst. In other words, compute an
** approximation for 10*log2(x).
*/
LogEst sqlite3LogEst(u64 x){
static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
+30 -6
View File
@@ -3390,11 +3390,15 @@ case OP_OpenEphemeral: {
break;
}
/* Opcode: SorterOpen P1 P2 * P4 *
/* Opcode: SorterOpen P1 P2 P3 P4 *
**
** This opcode works like OP_OpenEphemeral except that it opens
** a transient index that is specifically designed to sort large
** tables using an external merge-sort algorithm.
**
** If argument P3 is non-zero, then it indicates that the sorter may
** assume that a stable sort considering the first P3 fields of each
** key is sufficient to produce the required results.
*/
case OP_SorterOpen: {
VdbeCursor *pCx;
@@ -3406,7 +3410,25 @@ case OP_SorterOpen: {
pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db );
assert( pCx->pKeyInfo->enc==ENC(db) );
rc = sqlite3VdbeSorterInit(db, pCx);
rc = sqlite3VdbeSorterInit(db, pOp->p3, pCx);
break;
}
/* Opcode: SequenceTest P1 P2 * * *
** Synopsis: if( cursor[P1].ctr++ ) pc = P2
**
** P1 is a sorter cursor. If the sequence counter is currently zero, jump
** to P2. Regardless of whether or not the jump is taken, increment the
** the sequence value.
*/
case OP_SequenceTest: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC->pSorter );
if( (pC->seqCount++)==0 ){
pc = pOp->p2 - 1;
}
break;
}
@@ -4212,6 +4234,7 @@ case OP_SorterCompare: {
assert( pOp->p4type==P4_INT32 );
pIn3 = &aMem[pOp->p3];
nIgnore = pOp->p4.i;
res = 0;
rc = sqlite3VdbeSorterCompare(pC, pIn3, nIgnore, &res);
VdbeBranchTaken(res!=0,2);
if( res ){
@@ -4232,6 +4255,7 @@ case OP_SorterData: {
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
rc = sqlite3VdbeSorterRowkey(pC, pOut);
assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) );
break;
}
@@ -4461,7 +4485,7 @@ case OP_Rewind: { /* jump */
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
res = 1;
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
rc = sqlite3VdbeSorterRewind(pC, &res);
}else{
pCrsr = pC->pCursor;
assert( pCrsr );
@@ -4620,7 +4644,7 @@ case OP_IdxInsert: { /* in2 */
rc = ExpandBlob(pIn2);
if( rc==SQLITE_OK ){
if( isSorter(pC) ){
rc = sqlite3VdbeSorterWrite(db, pC, pIn2);
rc = sqlite3VdbeSorterWrite(pC, pIn2);
}else{
nKey = pIn2->n;
zKey = pIn2->z;
@@ -6323,8 +6347,8 @@ default: { /* This is really OP_Noop and OP_Explain */
#ifdef VDBE_PROFILE
{
u64 elapsed = sqlite3Hwtime() - start;
pOp->cycles += elapsed;
u64 endTime = sqlite3Hwtime();
if( endTime>start ) pOp->cycles += endTime - start;
pOp->cnt++;
}
#endif
+3 -3
View File
@@ -437,13 +437,13 @@ void sqlite3VdbeFrameDelete(VdbeFrame*);
int sqlite3VdbeFrameRestore(VdbeFrame *);
int sqlite3VdbeTransferError(Vdbe *p);
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
int sqlite3VdbeSorterInit(sqlite3 *, int, VdbeCursor *);
void sqlite3VdbeSorterReset(sqlite3 *, VdbeSorter *);
void sqlite3VdbeSorterClose(sqlite3 *, VdbeCursor *);
int sqlite3VdbeSorterRowkey(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterNext(sqlite3 *, const VdbeCursor *, int *);
int sqlite3VdbeSorterRewind(sqlite3 *, const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(sqlite3 *, const VdbeCursor *, Mem *);
int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#if !defined(SQLITE_OMIT_SHARED_CACHE) && SQLITE_THREADSAFE>0
+35 -30
View File
@@ -3137,10 +3137,14 @@ void sqlite3VdbeRecordUnpack(
** sqlite3VdbeSerialGet() and sqlite3MemCompare() functions. It is used
** in assert() statements to ensure that the optimized code in
** sqlite3VdbeRecordCompare() returns results with these two primitives.
**
** Return true if the result of comparison is equivalent to desiredResult.
** Return false if there is a disagreement.
*/
static int vdbeRecordCompareDebug(
int nKey1, const void *pKey1, /* Left key */
const UnpackedRecord *pPKey2 /* Right key */
const UnpackedRecord *pPKey2, /* Right key */
int desiredResult /* Correct answer */
){
u32 d1; /* Offset into aKey[] of next data element */
u32 idx1; /* Offset into aKey[] of next header element */
@@ -3152,6 +3156,7 @@ static int vdbeRecordCompareDebug(
Mem mem1;
pKeyInfo = pPKey2->pKeyInfo;
if( pKeyInfo->db==0 ) return 1;
mem1.enc = pKeyInfo->enc;
mem1.db = pKeyInfo->db;
/* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */
@@ -3202,7 +3207,7 @@ static int vdbeRecordCompareDebug(
if( pKeyInfo->aSortOrder[i] ){
rc = -rc; /* Invert the result for DESC sort order. */
}
return rc;
goto debugCompareEnd;
}
i++;
}while( idx1<szHdr1 && i<pPKey2->nField );
@@ -3216,7 +3221,15 @@ static int vdbeRecordCompareDebug(
/* rc==0 here means that one of the keys ran out of fields and
** all the fields up to that point were equal. Return the the default_rc
** value. */
return pPKey2->default_rc;
rc = pPKey2->default_rc;
debugCompareEnd:
if( desiredResult==0 && rc==0 ) return 1;
if( desiredResult<0 && rc<0 ) return 1;
if( desiredResult>0 && rc>0 ) return 1;
if( CORRUPT_DB ) return 1;
if( pKeyInfo->db->mallocFailed ) return 1;
return 0;
}
#endif
@@ -3229,7 +3242,8 @@ static int vdbeRecordCompareDebug(
static int vdbeCompareMemString(
const Mem *pMem1,
const Mem *pMem2,
const CollSeq *pColl
const CollSeq *pColl,
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
){
if( pMem1->enc==pColl->enc ){
/* The strings are already in the correct encoding. Call the
@@ -3252,6 +3266,7 @@ static int vdbeCompareMemString(
rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
sqlite3VdbeMemRelease(&c1);
sqlite3VdbeMemRelease(&c2);
if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
return rc;
}
}
@@ -3334,7 +3349,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
assert( !pColl || pColl->xCmp );
if( pColl ){
return vdbeCompareMemString(pMem1, pMem2, pColl);
return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
}
/* If a NULL pointer was passed as the collate function, fall through
** to the blob case and use memcmp(). */
@@ -3406,8 +3421,10 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
** fields that appear in both keys are equal, then pPKey2->default_rc is
** returned.
**
** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
** and return 0.
** If database corruption is discovered, set pPKey2->errCode to
** SQLITE_CORRUPT and return 0. If an OOM error is encountered,
** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
*/
int sqlite3VdbeRecordCompare(
int nKey1, const void *pKey1, /* Left key */
@@ -3438,7 +3455,7 @@ int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
if( d1>(unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
i = 0;
@@ -3517,14 +3534,16 @@ int sqlite3VdbeRecordCompare(
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
if( (d1+mem1.n) > (unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else if( pKeyInfo->aColl[i] ){
mem1.enc = pKeyInfo->enc;
mem1.db = pKeyInfo->db;
mem1.flags = MEM_Str;
mem1.z = (char*)&aKey1[d1];
rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]);
rc = vdbeCompareMemString(
&mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode
);
}else{
int nCmp = MIN(mem1.n, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
@@ -3544,7 +3563,7 @@ int sqlite3VdbeRecordCompare(
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else{
int nCmp = MIN(nStr, pRhs->n);
@@ -3564,11 +3583,7 @@ int sqlite3VdbeRecordCompare(
if( pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
assert( CORRUPT_DB
|| (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|| (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|| pKeyInfo->db->mallocFailed
);
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, rc) );
assert( mem1.zMalloc==0 ); /* See comment below */
return rc;
}
@@ -3587,9 +3602,7 @@ int sqlite3VdbeRecordCompare(
/* rc==0 here means that one or both of the keys ran out of fields and
** all the fields up to that point were equal. Return the the default_rc
** value. */
assert( CORRUPT_DB
|| pPKey2->default_rc==vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)
);
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, pPKey2->default_rc) );
return pPKey2->default_rc;
}
@@ -3686,11 +3699,7 @@ static int vdbeRecordCompareInt(
res = pPKey2->default_rc;
}
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|| CORRUPT_DB
);
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
return res;
}
@@ -3724,7 +3733,7 @@ static int vdbeRecordCompareString(
nStr = (serial_type-12) / 2;
if( (szHdr + nStr) > nKey1 ){
pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
nCmp = MIN( pPKey2->aMem[0].n, nStr );
@@ -3750,11 +3759,7 @@ static int vdbeRecordCompareString(
}
}
assert( (res==0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)==0)
|| (res<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|| (res>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|| CORRUPT_DB
);
assert( vdbeRecordCompareDebug(nKey1, pKey1, pPKey2, res) );
return res;
}
+1813 -501
View File
File diff suppressed because it is too large Load Diff
+257 -153
View File
@@ -227,7 +227,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
if( p && ExprHasProperty(p, EP_Unlikely) ){
pTerm->truthProb = sqlite3LogEst(p->iTable) - 99;
}else{
pTerm->truthProb = -1;
pTerm->truthProb = 1;
}
pTerm->pExpr = sqlite3ExprSkipCollate(p);
pTerm->wtFlags = wtFlags;
@@ -1956,7 +1956,8 @@ static void whereKeyStats(
iLower = 0;
iUpper = aSample[0].anLt[iCol];
}else{
iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol];
i64 nRow0 = sqlite3LogEstToInt(pIdx->aiRowLogEst[0]);
iUpper = i>=pIdx->nSample ? nRow0 : aSample[i].anLt[iCol];
iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
}
aStat[1] = (pIdx->nKeyCol>iCol ? pIdx->aAvgEq[iCol] : 1);
@@ -1975,6 +1976,29 @@ static void whereKeyStats(
}
#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */
/*
** If it is not NULL, pTerm is a term that provides an upper or lower
** bound on a range scan. Without considering pTerm, it is estimated
** that the scan will visit nNew rows. This function returns the number
** estimated to be visited after taking pTerm into account.
**
** If the user explicitly specified a likelihood() value for this term,
** then the return value is the likelihood multiplied by the number of
** input rows. Otherwise, this function assumes that an "IS NOT NULL" term
** has a likelihood of 0.50, and any other term a likelihood of 0.25.
*/
static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){
LogEst nRet = nNew;
if( pTerm ){
if( pTerm->truthProb<=0 ){
nRet += pTerm->truthProb;
}else if( (pTerm->wtFlags & TERM_VNULL)==0 ){
nRet -= 20; assert( 20==sqlite3LogEst(4) );
}
}
return nRet;
}
/*
** This function is used to estimate the number of rows that will be visited
** by scanning an index for a range of values. The range may have an upper
@@ -2067,7 +2091,7 @@ static int whereRangeScanEst(
/* Determine iLower and iUpper using ($P) only. */
if( nEq==0 ){
iLower = 0;
iUpper = p->aiRowEst[0];
iUpper = sqlite3LogEstToInt(p->aiRowLogEst[0]);
}else{
/* Note: this call could be optimized away - since the same values must
** have been requested when testing key $P in whereEqualScanEst(). */
@@ -2127,17 +2151,18 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
#endif
assert( pLower || pUpper );
/* TUNING: Each inequality constraint reduces the search space 4-fold.
** A BETWEEN operator, therefore, reduces the search space 16-fold */
nNew = nOut;
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ){
nNew -= 20; assert( 20==sqlite3LogEst(4) );
nOut--;
}
if( pUpper ){
nNew -= 20; assert( 20==sqlite3LogEst(4) );
nOut--;
}
assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
/* TUNING: If there is both an upper and lower limit, assume the range is
** reduced by an additional 75%. This means that, by default, an open-ended
** range query (e.g. col > ?) is assumed to match 1/4 of the rows in the
** index. While a closed range (e.g. col BETWEEN ? AND ?) is estimated to
** match 1/64 of the index. */
if( pLower && pUpper ) nNew -= 20;
nOut -= (pLower!=0) + (pUpper!=0);
if( nNew<10 ) nNew = 10;
if( nNew<nOut ) nOut = nNew;
pLoop->nOut = (LogEst)nOut;
@@ -2234,6 +2259,7 @@ static int whereInScanEst(
tRowcnt *pnRow /* Write the revised row estimate here */
){
Index *p = pBuilder->pNew->u.btree.pIndex;
i64 nRow0 = sqlite3LogEstToInt(p->aiRowLogEst[0]);
int nRecValid = pBuilder->nRecValid;
int rc = SQLITE_OK; /* Subfunction return code */
tRowcnt nEst; /* Number of rows for a single term */
@@ -2242,14 +2268,14 @@ static int whereInScanEst(
assert( p->aSample!=0 );
for(i=0; rc==SQLITE_OK && i<pList->nExpr; i++){
nEst = p->aiRowEst[0];
nEst = nRow0;
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];
if( nRowEst > nRow0 ) nRowEst = nRow0;
*pnRow = nRowEst;
WHERETRACE(0x10,("IN row estimate: est=%g\n", nRowEst));
}
@@ -3757,12 +3783,25 @@ static int whereLoopCheaperProperSubset(
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
** WHERE clause terms than Y and that every WHERE clause term used by X is
** also used by Y.
**
** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the
** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE
** clause terms covered, since some of the first nLTerm entries in aLTerm[]
** will be NULL (because they are skipped). That makes it more difficult
** to compare the loops. We could add extra code to do the comparison, and
** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this
** adjustment is sufficient minor, that it is very difficult to construct
** a test case where the extra code would improve the query plan. Better
** to avoid the added complexity and just omit cost adjustments to SKIPSCAN
** loops.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue;
if( whereLoopCheaperProperSubset(p, pTemplate) ){
/* Adjust pTemplate cost downward so that it is cheaper than its
** subset p */
@@ -3987,13 +4026,20 @@ static void whereLoopOutputAdjust(WhereClause *pWC, WhereLoop *pLoop){
if( pX==pTerm ) break;
if( pX->iParent>=0 && (&pWC->a[pX->iParent])==pTerm ) break;
}
if( j<0 ) pLoop->nOut += pTerm->truthProb;
if( j<0 ){
pLoop->nOut += (pTerm->truthProb<=0 ? pTerm->truthProb : -1);
}
}
}
/*
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the index pIndex.
** Try to match one more.
** We have so far matched pBuilder->pNew->u.btree.nEq terms of the
** index pIndex. Try to match one more.
**
** When this function is called, pBuilder->pNew->nOut contains the
** number of rows expected to be visited by filtering using the nEq
** terms only. If it is modified, this value is restored before this
** function returns.
**
** If pProbe->tnum==0, that means pIndex is a fake index used for the
** INTEGER PRIMARY KEY.
@@ -4019,7 +4065,6 @@ static int whereLoopAddBtreeIndex(
LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */
LogEst nRowEst; /* Estimated index selectivity */
LogEst rLogSize; /* Logarithm of table size */
WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */
@@ -4040,11 +4085,8 @@ static int whereLoopAddBtreeIndex(
assert( pNew->u.btree.nEq<=pProbe->nKeyCol );
if( pNew->u.btree.nEq < pProbe->nKeyCol ){
iCol = pProbe->aiColumn[pNew->u.btree.nEq];
nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
}else{
iCol = -1;
nRowEst = 0;
}
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
opMask, pProbe);
@@ -4055,18 +4097,23 @@ static int whereLoopAddBtreeIndex(
saved_prereq = pNew->prereq;
saved_nOut = pNew->nOut;
pNew->rSetup = 0;
rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
rLogSize = estLog(pProbe->aiRowLogEst[0]);
/* Consider using a skip-scan if there are no WHERE clause constraints
** available for the left-most terms of the index, and if the average
** number of repeats in the left-most terms is at least 18. The magic
** number 18 was found by experimentation to be the payoff point where
** skip-scan become faster than a full-scan.
*/
** number of repeats in the left-most terms is at least 18.
**
** The magic number 18 is selected on the basis that scanning 17 rows
** is almost always quicker than an index seek (even though if the index
** contains fewer than 2^17 rows we assume otherwise in other parts of
** the code). And, even if it is not, it should not be too much slower.
** On the other hand, the extra seeks could end up being significantly
** more expensive. */
assert( 42==sqlite3LogEst(18) );
if( pTerm==0
&& saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
LogEst nIter;
@@ -4074,34 +4121,40 @@ static int whereLoopAddBtreeIndex(
pNew->u.btree.nSkip++;
pNew->aLTerm[pNew->nLTerm++] = 0;
pNew->wsFlags |= WHERE_SKIPSCAN;
nIter = sqlite3LogEst(pProbe->aiRowEst[0]/pProbe->aiRowEst[saved_nEq+1]);
pNew->rRun = rLogSize + nIter;
pNew->nOut += nIter;
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter);
nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
pNew->nOut -= nIter;
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
pNew->nOut = saved_nOut;
}
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
LogEst rCostIdx;
LogEst nOutUnadjusted; /* nOut before IN() and WHERE adjustments */
int nIn = 0;
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nRecValid = pBuilder->nRecValid;
#endif
if( (pTerm->eOperator==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0)
if( (eOp==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;
if( whereLoopResize(db, pNew, pNew->nLTerm+1) ) break; /* OOM */
pNew->aLTerm[pNew->nLTerm++] = pTerm;
pNew->prereq = (saved_prereq | pTerm->prereqRight) & ~pNew->maskSelf;
pNew->rRun = rLogSize; /* Baseline cost is log2(N). Adjustments below */
if( pTerm->eOperator & WO_IN ){
assert( nInMul==0
|| (pNew->wsFlags & WHERE_COLUMN_NULL)!=0
|| (pNew->wsFlags & WHERE_COLUMN_IN)!=0
|| (pNew->wsFlags & WHERE_SKIPSCAN)!=0
);
if( eOp & WO_IN ){
Expr *pExpr = pTerm->pExpr;
pNew->wsFlags |= WHERE_COLUMN_IN;
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
@@ -4113,83 +4166,118 @@ static int whereLoopAddBtreeIndex(
}
assert( nIn>0 ); /* RHS always has 2 or more terms... The parser
** changes "x IN (?)" into "x=?". */
pNew->rRun += nIn;
pNew->u.btree.nEq++;
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_EQ) ){
assert(
(pNew->wsFlags & (WHERE_COLUMN_NULL|WHERE_COLUMN_IN|WHERE_SKIPSCAN))!=0
|| nInMul==0
);
}else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){
assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 );
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
if( iCol>=0 && pProbe->onError==OE_None ){
pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{
pNew->wsFlags |= WHERE_ONEROW;
}
}
pNew->u.btree.nEq++;
pNew->nOut = nRowEst + nInMul;
}else if( pTerm->eOperator & (WO_ISNULL) ){
}else if( eOp & WO_ISNULL ){
pNew->wsFlags |= WHERE_COLUMN_NULL;
pNew->u.btree.nEq++;
/* TUNING: IS NULL selects 2 rows */
nIn = 10; assert( 10==sqlite3LogEst(2) );
pNew->nOut = nRowEst + nInMul + nIn;
}else if( pTerm->eOperator & (WO_GT|WO_GE) ){
testcase( pTerm->eOperator & WO_GT );
testcase( pTerm->eOperator & WO_GE );
}else if( eOp & (WO_GT|WO_GE) ){
testcase( eOp & WO_GT );
testcase( eOp & WO_GE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_BTM_LIMIT;
pBtm = pTerm;
pTop = 0;
}else{
assert( pTerm->eOperator & (WO_LT|WO_LE) );
testcase( pTerm->eOperator & WO_LT );
testcase( pTerm->eOperator & WO_LE );
assert( eOp & (WO_LT|WO_LE) );
testcase( eOp & WO_LT );
testcase( eOp & WO_LE );
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
pTop = pTerm;
pBtm = (pNew->wsFlags & WHERE_BTM_LIMIT)!=0 ?
pNew->aLTerm[pNew->nLTerm-2] : 0;
}
/* At this point pNew->nOut is set to the number of rows expected to
** be visited by the index scan before considering term pTerm, or the
** values of nIn and nInMul. In other words, assuming that all
** "x IN(...)" terms are replaced with "x = ?". This block updates
** the value of pNew->nOut to account for pTerm (but not nIn/nInMul). */
assert( pNew->nOut==saved_nOut );
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
/* Adjust nOut and rRun for STAT3 range values */
assert( pNew->nOut==saved_nOut );
/* Adjust nOut using stat3/stat4 data. Or, if there is no stat3/stat4
** data, using some other estimate. */
whereRangeScanEst(pParse, pBuilder, pBtm, pTop, pNew);
}
}else{
int nEq = ++pNew->u.btree.nEq;
assert( eOp & (WO_ISNULL|WO_EQ|WO_IN) );
assert( pNew->nOut==saved_nOut );
if( pTerm->truthProb<=0 && iCol>=0 ){
assert( (eOp & WO_IN) || nIn==0 );
testcase( eOp & WO_IN );
pNew->nOut += pTerm->truthProb;
pNew->nOut -= nIn;
pNew->wsFlags |= WHERE_LIKELIHOOD;
}else{
#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, pBuilder, pExpr->pRight, &nOut);
}else if( (pTerm->eOperator & WO_IN)
&& !ExprHasProperty(pExpr, EP_xIsSelect) ){
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
assert( nOut==0 || rc==SQLITE_OK );
if( nOut ){
pNew->nOut = sqlite3LogEst(nOut);
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
}
}
tRowcnt nOut = 0;
if( nInMul==0
&& pProbe->nSample
&& pNew->u.btree.nEq<=pProbe->nSampleCol
&& OptimizationEnabled(db, SQLITE_Stat3)
&& ((eOp & WO_IN)==0 || !ExprHasProperty(pTerm->pExpr, EP_xIsSelect))
&& (pNew->wsFlags & WHERE_LIKELIHOOD)==0
){
Expr *pExpr = pTerm->pExpr;
if( (eOp & (WO_EQ|WO_ISNULL))!=0 ){
testcase( eOp & WO_EQ );
testcase( eOp & WO_ISNULL );
rc = whereEqualScanEst(pParse, pBuilder, pExpr->pRight, &nOut);
}else{
rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
}
assert( rc!=SQLITE_OK || nOut>0 );
if( rc==SQLITE_NOTFOUND ) rc = SQLITE_OK;
if( rc!=SQLITE_OK ) break; /* Jump out of the pTerm loop */
if( nOut ){
pNew->nOut = sqlite3LogEst(nOut);
if( pNew->nOut>saved_nOut ) pNew->nOut = saved_nOut;
pNew->nOut -= nIn;
}
}
if( nOut==0 )
#endif
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
/* Each row involves a step of the index, then a binary search of
** the main table */
pNew->rRun = sqlite3LogEstAdd(pNew->rRun,rLogSize>27 ? rLogSize-17 : 10);
{
pNew->nOut += (pProbe->aiRowLogEst[nEq] - pProbe->aiRowLogEst[nEq-1]);
if( eOp & WO_ISNULL ){
/* TUNING: If there is no likelihood() value, assume that a
** "col IS NULL" expression matches twice as many rows
** as (col=?). */
pNew->nOut += 10;
}
}
}
}
/* Step cost for each output row */
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut);
/* Set rCostIdx to the cost of visiting selected rows in index. Add
** it to pNew->rRun, which is currently set to the cost of the index
** seek only. Then, if this is a non-covering index, add the cost of
** visiting the rows in the main table. */
rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow;
pNew->rRun = sqlite3LogEstAdd(rLogSize, rCostIdx);
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, pNew->nOut + 16);
}
nOutUnadjusted = pNew->nOut;
pNew->rRun += nInMul + nIn;
pNew->nOut += nInMul + nIn;
whereLoopOutputAdjust(pBuilder->pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
if( pNew->wsFlags & WHERE_COLUMN_RANGE ){
pNew->nOut = saved_nOut;
}else{
pNew->nOut = nOutUnadjusted;
}
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
&& pNew->u.btree.nEq<(pProbe->nKeyCol + (pProbe->zName!=0))
){
@@ -4273,6 +4361,29 @@ static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
** Add all WhereLoop objects for a single table of the join where the table
** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
**
** The costs (WhereLoop.rRun) of the b-tree loops added by this function
** are calculated as follows:
**
** For a full scan, assuming the table (or index) contains nRow rows:
**
** cost = nRow * 3.0 // full-table scan
** cost = nRow * K // scan of covering index
** cost = nRow * (K+3.0) // scan of non-covering index
**
** where K is a value between 1.1 and 3.0 set based on the relative
** estimated average size of the index and table records.
**
** For an index scan, where nVisit is the number of index rows visited
** by the scan, and nSeek is the number of seek operations required on
** the index b-tree:
**
** cost = nSeek * (log(nRow) + K * nVisit) // covering index
** cost = nSeek * (log(nRow) + (K+3.0) * nVisit) // non-covering index
**
** Normally, nSeek is 1. nSeek values greater than 1 come about if the
** WHERE clause includes "x IN (....)" terms used in place of "x=?". Or when
** implicit "x IN (SELECT x FROM tbl)" terms are added for skip-scans.
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
@@ -4281,7 +4392,7 @@ static int whereLoopAddBtree(
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
Index sPk; /* A fake index object for the primary key */
tRowcnt aiRowEstPk[2]; /* The aiRowEst[] value for the sPk index */
LogEst aiRowEstPk[2]; /* The aiRowLogEst[] value for the sPk index */
i16 aiColumnPk = -1; /* The aColumn[] value for the sPk index */
SrcList *pTabList; /* The FROM clause */
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
@@ -4316,11 +4427,12 @@ static int whereLoopAddBtree(
memset(&sPk, 0, sizeof(Index));
sPk.nKeyCol = 1;
sPk.aiColumn = &aiColumnPk;
sPk.aiRowEst = aiRowEstPk;
sPk.aiRowLogEst = aiRowEstPk;
sPk.onError = OE_Replace;
sPk.pTable = pTab;
aiRowEstPk[0] = pTab->nRowEst;
aiRowEstPk[1] = 1;
sPk.szIdxRow = pTab->szTabRow;
aiRowEstPk[0] = pTab->nRowLogEst;
aiRowEstPk[1] = 0;
pFirst = pSrc->pTab->pIndex;
if( pSrc->notIndexed==0 ){
/* The real indices of the table are only considered if the
@@ -4329,7 +4441,7 @@ static int whereLoopAddBtree(
}
pProbe = &sPk;
}
rSize = sqlite3LogEst(pTab->nRowEst);
rSize = pTab->nRowLogEst;
rLogSize = estLog(rSize);
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
@@ -4379,6 +4491,7 @@ static int whereLoopAddBtree(
&& !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){
continue; /* Partial index inappropriate for this query */
}
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nSkip = 0;
pNew->nLTerm = 0;
@@ -4396,10 +4509,8 @@ static int whereLoopAddBtree(
/* Full table scan */
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: Cost of full table scan is 3*(N + log2(N)).
** + The extra 3 factor is to encourage the use of indexed lookups
** over full scans. FIXME */
pNew->rRun = sqlite3LogEstAdd(rSize,rLogSize) + 16;
/* TUNING: Cost of full table scan is (N*3.0). */
pNew->rRun = rSize + 16;
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
@@ -4426,35 +4537,16 @@ static int whereLoopAddBtree(
)
){
pNew->iSortIdx = b ? iSortIdx : 0;
/* TUNING: The base cost of an index scan is N + log2(N).
** The log2(N) is for the initial seek to the beginning and the N
** is for the scan itself. */
pNew->rRun = sqlite3LogEstAdd(rSize, rLogSize);
if( m==0 ){
/* TUNING: Cost of a covering index scan is K*(N + log2(N)).
** + The extra factor K of between 1.1 and 3.0 that depends
** on the relative sizes of the table and the index. K
** is smaller for smaller indices, thus favoring them.
** The upper bound on K (3.0) matches the penalty factor
** on a full table scan that tries to encourage the use of
** indexed lookups over full scans.
*/
pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
}else{
/* TUNING: The cost of scanning a non-covering index is multiplied
** by log2(N) to account for the binary search of the main table
** that must happen for each row of the index.
** TODO: Should there be a multiplier here, analogous to the 3x
** multiplier for a fulltable scan or covering index scan, to
** further discourage the use of an index scan? Or is the log2(N)
** term sufficient discouragement?
** TODO: What if some or all of the WHERE clause terms can be
** computed without reference to the original table. Then the
** penality should reduce to logK where K is the number of output
** rows.
*/
pNew->rRun += rLogSize;
/* The cost of visiting the index rows is N*K, where K is
** between 1.1 and 3.0, depending on the relative sizes of the
** index and table rows. If this is a non-covering index scan,
** also add the cost of visiting table rows (N*3.0). */
pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
if( m!=0 ){
pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
}
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
pNew->nOut = rSize;
@@ -4658,7 +4750,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
int iCur;
WhereClause tempWC;
WhereLoopBuilder sSubBuild;
WhereOrSet sSum, sCur, sPrev;
WhereOrSet sSum, sCur;
struct SrcList_item *pItem;
pWC = pBuilder->pWC;
@@ -4714,6 +4806,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
whereOrMove(&sSum, &sCur);
once = 0;
}else{
WhereOrSet sPrev;
whereOrMove(&sPrev, &sSum);
sSum.n = 0;
for(i=0; i<sPrev.n; i++){
@@ -4732,8 +4825,19 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
pNew->iSortIdx = 0;
memset(&pNew->u, 0, sizeof(pNew->u));
for(i=0; rc==SQLITE_OK && i<sSum.n; i++){
/* TUNING: Multiple by 3.5 for the secondary table lookup */
pNew->rRun = sSum.a[i].rRun + 18;
/* TUNING: Currently sSum.a[i].rRun is set to the sum of the costs
** of all sub-scans required by the OR-scan. However, due to rounding
** errors, it may be that the cost of the OR-scan is equal to its
** most expensive sub-scan. Add the smallest possible penalty
** (equivalent to multiplying the cost by 1.07) to ensure that
** this does not happen. Otherwise, for WHERE clauses such as the
** following where there is an index on "y":
**
** WHERE likelihood(x=?, 0.99) OR y=?
**
** the planner may elect to "OR" together a full-table scan and an
** index lookup. And other similarly odd results. */
pNew->rRun = sSum.a[i].rRun + 1;
pNew->nOut = sSum.a[i].nOut;
pNew->prereq = sSum.a[i].prereq;
rc = whereLoopInsert(pBuilder, pNew);
@@ -4857,14 +4961,6 @@ static i8 wherePathSatisfiesOrderBy(
*/
assert( pOrderBy!=0 );
/* Sortability of virtual tables is determined by the xBestIndex method
** of the virtual table itself */
if( pLast->wsFlags & WHERE_VIRTUALTABLE ){
testcase( nLoop>0 ); /* True when outer loops are one-row and match
** no ORDER BY terms */
return pLast->u.vtab.isOrdered;
}
if( nLoop && OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return 0;
nOrderBy = pOrderBy->nExpr;
@@ -4877,7 +4973,10 @@ static i8 wherePathSatisfiesOrderBy(
for(iLoop=0; isOrderDistinct && obSat<obDone && iLoop<=nLoop; iLoop++){
if( iLoop>0 ) ready |= pLoop->maskSelf;
pLoop = iLoop<nLoop ? pPath->aLoop[iLoop] : pLast;
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){
if( pLoop->u.vtab.isOrdered ) obSat = obDone;
break;
}
iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor;
/* Mark off any ORDER BY term X that is a column in the table of
@@ -5184,22 +5283,27 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask);
if( isOrdered>=0 && isOrdered<nOrderBy ){
/* TUNING: Estimated cost of sorting is N*log(N).
** If the order-by clause has X terms but only the last Y terms
** are out of order, then block-sorting will reduce the sorting
** cost to N*log(N)*log(Y/X). The log(Y/X) term is computed
** by rScale.
** TODO: Should the sorting cost get a small multiplier to help
** discourage the use of sorting and encourage the use of index
** scans instead?
*/
/* TUNING: Estimated cost of a full external sort, where N is
** the number of rows to sort is:
**
** cost = (3.0 * N * log(N)).
**
** Or, if the order-by clause has X terms but only the last Y
** terms are out of order, then block-sorting will reduce the
** sorting cost to:
**
** cost = (3.0 * N * log(N)) * (Y/X)
**
** The (Y/X) term is implemented using stack variable rScale
** below. */
LogEst rScale, rSortCost;
assert( nOrderBy>0 );
assert( nOrderBy>0 && 66==sqlite3LogEst(100) );
rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
rSortCost = nRowEst + estLog(nRowEst) + rScale;
rSortCost = nRowEst + estLog(nRowEst) + rScale + 16;
/* TUNING: The cost of implementing DISTINCT using a B-TREE is
** also N*log(N) but it has a larger constant of proportionality.
** Multiply by 3.0. */
** similar but with a larger constant of proportionality.
** Multiply by an additional factor of 3.0. */
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
rSortCost += 16;
}
+1
View File
@@ -458,3 +458,4 @@ struct WhereInfo {
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
#define WHERE_LIKELIHOOD 0x00020000 /* A likelihood() is affecting nOut */
+30 -12
View File
@@ -103,12 +103,21 @@ do_test analyze3-1.1.1 {
}
} {1}
do_execsql_test analyze3-1.1.x {
SELECT count(*) FROM t1 WHERE x>200 AND x<300;
SELECT count(*) FROM t1 WHERE x>0 AND x<1100;
} {99 1000}
# The first of the following two SELECT statements visits 99 rows. So
# it is better to use the index. But the second visits every row in
# the table (1000 in total) so it is better to do a full-table scan.
#
do_eqp_test analyze3-1.1.2 {
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
do_eqp_test analyze3-1.1.3 {
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}}
} {0 0 0 {SCAN TABLE t1}}
do_test analyze3-1.1.4 {
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
@@ -125,17 +134,17 @@ do_test analyze3-1.1.6 {
} {199 0 14850}
do_test analyze3-1.1.7 {
sf_execsql { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 }
} {2000 0 499500}
} {999 999 499500}
do_test analyze3-1.1.8 {
set l [string range "0" 0 end]
set u [string range "1100" 0 end]
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
} {2000 0 499500}
} {999 999 499500}
do_test analyze3-1.1.9 {
set l [expr int(0)]
set u [expr int(1100)]
sf_execsql { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u }
} {2000 0 499500}
} {999 999 499500}
# The following tests are similar to the block above. The difference is
@@ -152,12 +161,17 @@ do_test analyze3-1.2.1 {
ANALYZE;
}
} {}
do_execsql_test analyze3-2.1.x {
SELECT count(*) FROM t2 WHERE x>1 AND x<2;
SELECT count(*) FROM t2 WHERE x>0 AND x<99;
} {200 990}
do_eqp_test analyze3-1.2.2 {
SELECT sum(y) FROM t2 WHERE x>1 AND x<2
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
do_eqp_test analyze3-1.2.3 {
SELECT sum(y) FROM t2 WHERE x>0 AND x<99
} {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}}
} {0 0 0 {SCAN TABLE t2}}
do_test analyze3-1.2.4 {
sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 }
} {161 0 4760}
@@ -173,17 +187,17 @@ do_test analyze3-1.2.6 {
} {161 0 integer integer 4760}
do_test analyze3-1.2.7 {
sf_execsql { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 }
} {1981 0 490555}
} {999 999 490555}
do_test analyze3-1.2.8 {
set l [string range "0" 0 end]
set u [string range "99" 0 end]
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
} {1981 0 text text 490555}
} {999 999 text text 490555}
do_test analyze3-1.2.9 {
set l [expr int(0)]
set u [expr int(99)]
sf_execsql {SELECT typeof($l), typeof($u), sum(y) FROM t2 WHERE x>$l AND x<$u}
} {1981 0 integer integer 490555}
} {999 999 integer integer 490555}
# Same tests a third time. This time, column x has INTEGER affinity and
# is not the leftmost column of the table. This triggered a bug causing
@@ -199,12 +213,16 @@ do_test analyze3-1.3.1 {
ANALYZE;
}
} {}
do_execsql_test analyze3-1.3.x {
SELECT count(*) FROM t3 WHERE x>200 AND x<300;
SELECT count(*) FROM t3 WHERE x>0 AND x<1100
} {99 1000}
do_eqp_test analyze3-1.3.2 {
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
do_eqp_test analyze3-1.3.3 {
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}}
} {0 0 0 {SCAN TABLE t3}}
do_test analyze3-1.3.4 {
sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 }
@@ -221,17 +239,17 @@ do_test analyze3-1.3.6 {
} {199 0 14850}
do_test analyze3-1.3.7 {
sf_execsql { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 }
} {2000 0 499500}
} {999 999 499500}
do_test analyze3-1.3.8 {
set l [string range "0" 0 end]
set u [string range "1100" 0 end]
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
} {2000 0 499500}
} {999 999 499500}
do_test analyze3-1.3.9 {
set l [expr int(0)]
set u [expr int(1100)]
sf_execsql { SELECT sum(y) FROM t3 WHERE x>$l AND x<$u }
} {2000 0 499500}
} {999 999 499500}
#-------------------------------------------------------------------------
# Test that the values of bound SQL variables may be used for the LIKE
+5 -5
View File
@@ -566,7 +566,7 @@ foreach {tn schema} {
drop_all_tables
do_test 13.1 {
execsql {
CREATE TABLE t1(a, b, c);
CREATE TABLE t1(a, b, c, d);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b, c);
}
@@ -577,16 +577,16 @@ do_test 13.1 {
execsql ANALYZE
} {}
do_eqp_test 13.2.1 {
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<20
SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12
} {/SEARCH TABLE t1 USING INDEX i1/}
do_eqp_test 13.2.2 {
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<20
SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12
} {/SEARCH TABLE t1 USING INDEX i1/}
do_eqp_test 13.3.1 {
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<20
SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12
} {/SEARCH TABLE t1 USING INDEX i2/}
do_eqp_test 13.3.2 {
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<20
SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12
} {/SEARCH TABLE t1 USING INDEX i2/}
#-------------------------------------------------------------------------
+2
View File
@@ -97,6 +97,8 @@ do_test autoindex1-210 {
PRAGMA automatic_index=ON;
ANALYZE;
UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t1';
-- Table t2 actually contains 8 rows.
UPDATE sqlite_stat1 SET stat='16' WHERE tbl='t2';
ANALYZE sqlite_master;
SELECT b, (SELECT d FROM t2 WHERE c=a) FROM t1;
}
+251
View File
@@ -0,0 +1,251 @@
# 2014-04-26
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix cost
do_execsql_test 1.1 {
CREATE TABLE t3(id INTEGER PRIMARY KEY, b NOT NULL);
CREATE TABLE t4(c, d, e);
CREATE UNIQUE INDEX i3 ON t3(b);
CREATE UNIQUE INDEX i4 ON t4(c, d);
}
do_eqp_test 1.2 {
SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d;
} {
0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3}
0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)}
}
do_execsql_test 2.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
}
# It is better to use an index for ORDER BY than sort externally, even
# if the index is a non-covering index.
do_eqp_test 2.2 {
SELECT * FROM t1 ORDER BY a;
} {
0 0 0 {SCAN TABLE t1 USING INDEX i1}
}
do_execsql_test 3.1 {
CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
CREATE INDEX t5b ON t5(b);
CREATE INDEX t5c ON t5(c);
CREATE INDEX t5d ON t5(d);
CREATE INDEX t5e ON t5(e);
CREATE INDEX t5f ON t5(f);
CREATE INDEX t5g ON t5(g);
}
do_eqp_test 3.2 {
SELECT a FROM t5
WHERE b IS NULL OR c IS NULL OR d IS NULL
ORDER BY a;
} {
0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)}
0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)}
0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
#-------------------------------------------------------------------------
# If there is no likelihood() or stat3 data, SQLite assumes that a closed
# range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint)
# visits 1/64 of the rows in a table.
#
# Note: 1/63 =~ 0.016
# Note: 1/65 =~ 0.015
#
reset_db
do_execsql_test 4.1 {
CREATE TABLE t1(a, b);
CREATE INDEX i1 ON t1(a);
CREATE INDEX i2 ON t1(b);
}
do_eqp_test 4.2 {
SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
}
do_eqp_test 4.3 {
SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?;
} {
0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 5.1 {
CREATE TABLE t2(x, y);
CREATE INDEX t2i1 ON t2(x);
}
do_eqp_test 5.2 {
SELECT * FROM t2 ORDER BY x, y;
} {
0 0 0 {SCAN TABLE t2 USING INDEX t2i1}
0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
}
do_eqp_test 5.3 {
SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid;
} {
0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
# where7.test, where8.test:
#
do_execsql_test 6.1 {
CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c);
CREATE INDEX t3i1 ON t3(b);
CREATE INDEX t3i2 ON t3(c);
}
do_eqp_test 6.2 {
SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a
} {
0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)}
0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 7.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g);
CREATE INDEX t1b ON t1(b);
CREATE INDEX t1c ON t1(c);
CREATE INDEX t1d ON t1(d);
CREATE INDEX t1e ON t1(e);
CREATE INDEX t1f ON t1(f);
CREATE INDEX t1g ON t1(g);
}
do_eqp_test 7.2 {
SELECT a FROM t1
WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL)
ORDER BY a
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
do_eqp_test 7.3 {
SELECT rowid FROM t1
WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL)
OR (b NOT NULL AND c IS NULL AND d NOT NULL)
OR (b NOT NULL AND c NOT NULL AND d IS NULL)
} {
0 0 0 {SCAN TABLE t1}
}
do_eqp_test 7.4 {
SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL
} {
0 0 0 {SCAN TABLE t1}
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 8.1 {
CREATE TABLE composer(
cid INTEGER PRIMARY KEY,
cname TEXT
);
CREATE TABLE album(
aid INTEGER PRIMARY KEY,
aname TEXT
);
CREATE TABLE track(
tid INTEGER PRIMARY KEY,
cid INTEGER REFERENCES composer,
aid INTEGER REFERENCES album,
title TEXT
);
CREATE INDEX track_i1 ON track(cid);
CREATE INDEX track_i2 ON track(aid);
}
do_eqp_test 8.2 {
SELECT DISTINCT aname
FROM album, composer, track
WHERE cname LIKE '%bach%'
AND unlikely(composer.cid=track.cid)
AND unlikely(album.aid=track.aid);
} {
0 0 2 {SCAN TABLE track}
0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)}
0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
}
#-------------------------------------------------------------------------
#
do_execsql_test 9.1 {
CREATE TABLE t1(
a,b,c,d,e, f,g,h,i,j,
k,l,m,n,o, p,q,r,s,t
);
CREATE INDEX i1 ON t1(k,l,m,n,o,p,q,r,s,t);
}
do_test 9.2 {
for {set i 0} {$i < 100} {incr i} {
execsql { INSERT INTO t1 DEFAULT VALUES }
}
execsql {
ANALYZE;
CREATE INDEX i2 ON t1(a,b,c,d,e,f,g,h,i,j);
}
} {}
set L [list a=? b=? c=? d=? e=? f=? g=? h=? i=? j=?]
foreach {tn nTerm nRow} {
1 1 10
2 2 9
3 3 8
4 4 7
5 5 6
6 6 5
7 7 5
8 8 5
9 9 5
10 10 5
} {
set w [join [lrange $L 0 [expr $nTerm-1]] " AND "]
set p1 [expr ($nRow-1) / 100.0]
set p2 [expr ($nRow+1) / 100.0]
set sql1 "SELECT * FROM t1 WHERE likelihood(k=?, $p1) AND $w"
set sql2 "SELECT * FROM t1 WHERE likelihood(k=?, $p2) AND $w"
do_eqp_test 9.3.$tn.1 $sql1 {/INDEX i1/}
do_eqp_test 9.3.$tn.2 $sql2 {/INDEX i2/}
}
finish_test
+3 -2
View File
@@ -884,9 +884,10 @@ do_execsql_test e_createtable-3.3.1 {
);
} {}
# EVIDENCE-OF: R-10288-43169 For the purposes of the DEFAULT clause, an
# EVIDENCE-OF: R-36381-62919 For the purposes of the DEFAULT clause, an
# expression is considered constant provided that it does not contain
# any sub-queries or string constants enclosed in double quotes.
# any sub-queries, column or table references, or string literals
# enclosed in double-quotes instead of single-quotes.
#
do_createtable_tests 3.4.1 -error {
default value of column [x] is not constant
+6 -5
View File
@@ -135,9 +135,9 @@ reset_db
#
# This also tests that foreign key constraints are disabled by default.
#
# EVIDENCE-OF: R-59578-04990 Foreign key constraints are disabled by
# EVIDENCE-OF: R-44261-39702 Foreign key constraints are disabled by
# default (for backwards compatibility), so must be enabled separately
# for each database connection separately.
# for each database connection.
#
drop_all_tables
do_test e_fkey-4.1 {
@@ -163,9 +163,10 @@ do_test e_fkey-4.2 {
} {world}
#-------------------------------------------------------------------------
# EVIDENCE-OF: R-15278-54456 The application can can also use a PRAGMA
# EVIDENCE-OF: R-08013-37737 The application can also use a PRAGMA
# foreign_keys statement to determine if foreign keys are currently
# enabled.
#
# This also tests the example code in section 2 of foreignkeys.in.
#
@@ -2990,8 +2991,8 @@ if {[clang_sanitize_address]==0} {
# The setting of the recursive_triggers pragma does not affect foreign
# key actions.
#
# EVIDENCE-OF: R-51769-32730 The PRAGMA recursive_triggers setting does
# not not affect the operation of foreign key actions.
# EVIDENCE-OF: R-44355-00270 The PRAGMA recursive_triggers setting does
# not affect the operation of foreign key actions.
#
foreach recursive_triggers_setting [list 0 1 ON OFF] {
drop_all_tables
+6 -6
View File
@@ -312,8 +312,8 @@ do_eqp_test 4.2.3 {
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)}
}
do_eqp_test 4.2.4 {
@@ -321,8 +321,8 @@ do_eqp_test 4.2.4 {
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)}
}
do_eqp_test 4.2.5 {
@@ -330,8 +330,8 @@ do_eqp_test 4.2.5 {
} {
1 0 0 {SCAN TABLE t1}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2}
2 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 USING INDEX t2i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)}
}
+3 -2
View File
@@ -145,11 +145,11 @@ do_test index6-2.1 {
execsql {
CREATE TABLE t2(a,b);
INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000;
UPDATE t2 SET a=NULL WHERE b%5==0;
UPDATE t2 SET a=NULL WHERE b%2==0;
CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL;
SELECT count(*) FROM t2 WHERE a IS NOT NULL;
}
} {800}
} {500}
do_test index6-2.2 {
execsql {
EXPLAIN QUERY PLAN
@@ -157,6 +157,7 @@ do_test index6-2.2 {
}
} {/.* TABLE t2 USING INDEX t2a1 .*/}
ifcapable stat4||stat3 {
execsql ANALYZE
do_test index6-2.3stat4 {
execsql {
EXPLAIN QUERY PLAN
+42
View File
@@ -880,6 +880,48 @@ do_malloc_test 39 -tclprep {
db close
}
reset_db
add_test_utf16bin_collate db
do_execsql_test 40.1 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES('fghij');
INSERT INTO t1 VALUES('pqrst');
INSERT INTO t1 VALUES('abcde');
INSERT INTO t1 VALUES('uvwxy');
INSERT INTO t1 VALUES('klmno');
}
do_execsql_test 40.2 {
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
} {abcde fghij klmno pqrst uvwxy}
do_faultsim_test 40.3 -faults oom-trans* -body {
execsql {
SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
}
} -test {
faultsim_test_result {0 {abcde fghij klmno pqrst uvwxy}}
faultsim_integrity_check
}
reset_db
add_test_utf16bin_collate db
set big [string repeat x 200]
do_execsql_test 41.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a COLLATE utf16bin);
INSERT INTO t1 VALUES('fghij' || $::big);
INSERT INTO t1 VALUES('pqrst' || $::big);
INSERT INTO t1 VALUES('abcde' || $::big);
INSERT INTO t1 VALUES('uvwxy' || $::big);
INSERT INTO t1 VALUES('klmno' || $::big);
CREATE INDEX i1 ON t1(a);
}
do_faultsim_test 41.2 -faults oom* -body {
execsql { SELECT * FROM t1 WHERE a = ('abcde' || $::big)}
} -test {
faultsim_test_result [list 0 "abcde$::big"]
faultsim_integrity_check
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}
+22 -1
View File
@@ -25,7 +25,6 @@ if {!$MEMDEBUG} {
return
}
# Construct a test database
#
forcedelete test.db.bu
@@ -116,6 +115,28 @@ ifcapable stat3 {
}
}
do_execsql_test 7.0 {
PRAGMA cache_size = 5;
}
do_faultsim_test 7 -faults oom-trans* -prep {
if {$iFail < 500} { set iFail 2000 }
if {$iFail > 1215} { set iFail 2000 }
} -body {
execsql {
WITH r(x,y) AS (
SELECT 1, randomblob(100)
UNION ALL
SELECT x+1, randomblob(100) FROM r
LIMIT 1000
)
SELECT count(x), length(y) FROM r GROUP BY (x%5)
}
} -test {
set res [list 200 100 200 100 200 100 200 100 200 100]
faultsim_test_result [list 0 $res]
}
# Ensure that no file descriptors were leaked.
do_test malloc-99.X {
catch {db close}
+2 -2
View File
@@ -80,12 +80,12 @@ do_execsql_test 2.1a {
EXPLAIN QUERY PLAN
SELECT * FROM t2 WHERE a=0 ORDER BY a, b, c;
} {~/B-TREE/}
do_execsql_test 2.1b {
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE a=0 ORDER BY a, b, c;
SELECT * FROM t1 WHERE likelihood(a=0, 0.05) ORDER BY a, b, c;
} {/B-TREE/}
do_execsql_test 2.2 {
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
+106
View File
@@ -0,0 +1,106 @@
# 2014-04-25
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing ORDER BY optimizations on joins
# that involve virtual tables.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix orderby7
ifcapable !fts3 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE fts USING fts3(content TEXT);
INSERT INTO fts(rowid,content)
VALUES(1,'this is a test of the fts3 virtual'),
(2,'table used as part of a join together'),
(3,'with the DISTINCT keyword. There was'),
(4,'a bug at one time (2013-06 through 2014-04)'),
(5,'that prevented this from working correctly.'),
(11,'a row that occurs twice'),
(12,'a row that occurs twice');
CREATE TABLE t1(x TEXT PRIMARY KEY, y);
INSERT OR IGNORE INTO t1 SELECT content, rowid+100 FROM fts;
} {}
do_execsql_test 1.1 {
SELECT DISTINCT fts.rowid, t1.y
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x
ORDER BY y;
} {11 111 12 111}
do_execsql_test 1.2 {
SELECT DISTINCT fts.rowid, t1.x
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x
ORDER BY 1;
} {11 {a row that occurs twice} 12 {a row that occurs twice}}
do_execsql_test 1.3 {
SELECT DISTINCT t1.x
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x
ORDER BY 1;
} {{a row that occurs twice}}
do_execsql_test 1.4 {
SELECT t1.x
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x
ORDER BY 1;
} {{a row that occurs twice} {a row that occurs twice}}
do_execsql_test 1.5 {
SELECT DISTINCT t1.x
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x;
} {{a row that occurs twice}}
do_execsql_test 1.6 {
SELECT t1.x
FROM fts, t1
WHERE fts MATCH 'that twice'
AND content=x;
} {{a row that occurs twice} {a row that occurs twice}}
do_execsql_test 2.1 {
SELECT DISTINCT t1.x
FROM fts, t1
WHERE fts.rowid=11
AND content=x
ORDER BY fts.rowid;
} {{a row that occurs twice}}
do_execsql_test 2.2 {
SELECT DISTINCT t1.*
FROM fts, t1
WHERE fts.rowid=11
AND content=x
ORDER BY fts.rowid;
} {{a row that occurs twice} 111}
do_execsql_test 2.3 {
SELECT DISTINCT t1.*
FROM fts, t1
WHERE fts.rowid=11
AND content=x
ORDER BY t1.y
} {{a row that occurs twice} 111}
finish_test
+8 -1
View File
@@ -112,6 +112,7 @@ set allquicktests [test_set $alltests -exclude {
incrvacuum_ioerr.test autovacuum_crash.test btree8.test shared_err.test
vtab_err.test walslow.test walcrash.test walcrash3.test
walthread.test rtree3.test indexfault.test securedel2.test
sort3.test sort4.test
}]
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
@@ -331,6 +332,12 @@ test_suite "coverage-analyze" -description {
analyze.test analyzeB.test mallocA.test
}
test_suite "coverage-sorter" -description {
Coverage tests for file vdbesort.c.
} -files {
sort.test sortfault.test
}
lappend ::testsuitelist xxx
#-------------------------------------------------------------------------
@@ -462,7 +469,7 @@ test_suite "multithread" -description {
} -files {
delete.test delete2.test insert.test rollback.test select1.test
select2.test trans.test update.test vacuum.test types.test
types2.test types3.test
types2.test types3.test sort4.test
} -shutdown {
catch {db close}
sqlite3_shutdown
+65
View File
@@ -21,6 +21,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix selectA
ifcapable !compound {
finish_test
@@ -1310,4 +1311,68 @@ do_execsql_test selectA-3.98 {
SELECT n FROM xyz ORDER BY +n;
} {MAD MAD+ MAD++}
#-------------------------------------------------------------------------
# At one point the following code exposed a temp register reuse problem.
#
proc f {args} { return 1 }
db func f f
do_execsql_test 4.1.1 {
CREATE TABLE t4(a, b);
CREATE TABLE t5(c, d);
INSERT INTO t5 VALUES(1, 'x');
INSERT INTO t5 VALUES(2, 'x');
INSERT INTO t4 VALUES(3, 'x');
INSERT INTO t4 VALUES(4, 'x');
CREATE INDEX i1 ON t4(a);
CREATE INDEX i2 ON t5(c);
}
do_eqp_test 4.1.2 {
SELECT c, d FROM t5
UNION ALL
SELECT a, b FROM t4 WHERE f()==f()
ORDER BY 1,2
} {
1 0 0 {SCAN TABLE t5 USING INDEX i2}
1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
2 0 0 {SCAN TABLE t4 USING INDEX i1}
2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY}
0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)}
}
do_execsql_test 4.1.3 {
SELECT c, d FROM t5
UNION ALL
SELECT a, b FROM t4 WHERE f()==f()
ORDER BY 1,2
} {
1 x 2 x 3 x 4 x
}
do_execsql_test 4.2.1 {
CREATE TABLE t6(a, b);
CREATE TABLE t7(c, d);
INSERT INTO t7 VALUES(2, 9);
INSERT INTO t6 VALUES(3, 0);
INSERT INTO t6 VALUES(4, 1);
INSERT INTO t7 VALUES(5, 6);
INSERT INTO t6 VALUES(6, 0);
INSERT INTO t7 VALUES(7, 6);
CREATE INDEX i6 ON t6(a);
CREATE INDEX i7 ON t7(c);
}
do_execsql_test 4.2.2 {
SELECT c, f(d,c,d,c,d) FROM t7
UNION ALL
SELECT a, b FROM t6
ORDER BY 1,2
} {/2 . 3 . 4 . 5 . 6 . 7 ./}
finish_test
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/tclsh
#
# This script displays the field of rectangles used by --testset rtree
# of speedtest1. Run this script as follows:
#
# rm test.db
# ./speedtest1 --testset rtree --size 25 test.db
# sqlite3 --separator ' ' test.db 'SELECT * FROM rt1' >data.txt
# wish show_speedtest1_rtree.tcl
#
# The filename "data.txt" is hard coded into this script and so that name
# must be used on lines 3 and 4 above. Elsewhere, different filenames can
# be used. The --size N parameter can be adjusted as desired.
#
package require Tk
set f [open data.txt rb]
set data [read $f]
close $f
canvas .c
frame .b
button .b.b1 -text X-Y -command refill-xy
button .b.b2 -text X-Z -command refill-xz
button .b.b3 -text Y-Z -command refill-yz
pack .b.b1 .b.b2 .b.b3 -side left
pack .c -side top -fill both -expand 1
pack .b -side top
proc resize_canvas_to_fit {} {
foreach {x0 y0 x1 y1} [.c bbox all] break
set w [expr {$x1-$x0}]
set h [expr {$y1-$y0}]
.c config -width $w -height $h
}
proc refill-xy {} {
.c delete all
foreach {id x0 x1 y0 y1 z0 z1} $::data {
.c create rectangle $x0 $y0 $x1 $y1
}
.c scale all 0 0 0.05 0.05
resize_canvas_to_fit
}
proc refill-xz {} {
.c delete all
foreach {id x0 x1 y0 y1 z0 z1} $::data {
.c create rectangle $x0 $z0 $x1 $z1
}
.c scale all 0 0 0.05 0.05
resize_canvas_to_fit
}
proc refill-yz {} {
.c delete all
foreach {id x0 x1 y0 y1 z0 z1} $::data {
.c create rectangle $y0 $z0 $y1 $z1
}
.c scale all 0 0 0.05 0.05
resize_canvas_to_fit
}
refill-xy
+1
View File
@@ -74,6 +74,7 @@ do_execsql_test skipscan2-1.4 {
-- of a skip-scan. So make a manual adjustment to the stat1 table
-- to make it seem like there are many more.
UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1';
UPDATE sqlite_stat1 SET stat='10000 1' WHERE idx='sqlite_autoindex_people_1';
ANALYZE sqlite_master;
}
db cache flush
+176 -3
View File
@@ -8,10 +8,10 @@
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the CREATE TABLE statement.
#
# $Id: sort.test,v 1.25 2005/11/14 22:29:06 drh Exp $
# This file implements regression tests for SQLite library. The
# focus of this file is testing the sorter (code in vdbesort.c).
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -464,4 +464,177 @@ do_test sort-12.1 {
}
} {1 2 xxx 1 3 yyy 1 1 zzz}
#-------------------------------------------------------------------------
# Check that the sorter in vdbesort.c sorts in a stable fashion.
#
do_execsql_test sort-13.0 {
CREATE TABLE t10(a, b);
}
do_test sort-13.1 {
db transaction {
for {set i 0} {$i < 100000} {incr i} {
execsql { INSERT INTO t10 VALUES( $i/10, $i%10 ) }
}
}
} {}
do_execsql_test sort-13.2 {
SELECT a, b FROM t10 ORDER BY a;
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
do_execsql_test sort-13.3 {
PRAGMA cache_size = 5;
SELECT a, b FROM t10 ORDER BY a;
} [db eval {SELECT a, b FROM t10 ORDER BY a, b}]
#-------------------------------------------------------------------------
# Sort some large ( > 4KiB) records.
#
proc cksum {x} {
set i1 1
set i2 2
binary scan $x c* L
foreach {a b} $L {
set i1 [expr (($i2<<3) + $a) & 0x7FFFFFFF]
set i2 [expr (($i1<<3) + $b) & 0x7FFFFFFF]
}
list $i1 $i2
}
db func cksum cksum
do_execsql_test sort-14.0 {
PRAGMA cache_size = 5;
CREATE TABLE t11(a, b);
INSERT INTO t11 VALUES(randomblob(5000), NULL);
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --2
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --3
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --4
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --5
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --6
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --7
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --8
INSERT INTO t11 SELECT randomblob(5000), NULL FROM t11; --9
UPDATE t11 SET b = cksum(a);
}
foreach {tn mmap_limit} {
1 0
2 1000000
} {
do_test sort-14.$tn {
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit
set prev ""
db eval { SELECT * FROM t11 ORDER BY b } {
if {$b != [cksum $a]} {error "checksum failed"}
if {[string compare $b $prev] < 0} {error "sort failed"}
set prev $b
}
set {} {}
} {}
}
#-------------------------------------------------------------------------
#
foreach {tn mmap_limit nWorker tmpstore coremutex fakeheap softheaplimit} {
1 0 3 file true false 0
2 0 3 file true true 0
3 0 0 file true false 0
4 1000000 3 file true false 0
5 0 0 memory false true 0
6 0 0 file false true 1000000
7 0 0 file false true 10000
} {
db close
sqlite3_shutdown
sqlite3_config_worker_threads $nWorker
if {$coremutex} {
sqlite3_config multithread
} else {
sqlite3_config singlethread
}
sqlite3_initialize
sorter_test_fakeheap $fakeheap
sqlite3_soft_heap_limit $softheaplimit
reset_db
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $mmap_limit
execsql "PRAGMA temp_store = $tmpstore"
set ten [string repeat X 10300]
set one [string repeat y 200]
if {$softheaplimit} {
execsql { PRAGMA cache_size = 20 };
} else {
execsql { PRAGMA cache_size = 5 };
}
do_execsql_test 15.$tn.1 {
WITH rr AS (
SELECT 4, $ten UNION ALL
SELECT 2, $one UNION ALL
SELECT 1, $ten UNION ALL
SELECT 3, $one
)
SELECT * FROM rr ORDER BY 1;
} [list 1 $ten 2 $one 3 $one 4 $ten]
do_execsql_test 15.$tn.2 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(4);
INSERT INTO t1 VALUES(5);
INSERT INTO t1 VALUES(3);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(6);
INSERT INTO t1 VALUES(1);
CREATE INDEX i1 ON t1(a);
SELECT * FROM t1 ORDER BY a;
} {1 2 3 4 5 6}
do_execsql_test 15.$tn.3 {
WITH rr AS (
SELECT 4, $ten UNION ALL
SELECT 2, $one
)
SELECT * FROM rr ORDER BY 1;
} [list 2 $one 4 $ten]
sorter_test_fakeheap 0
}
db close
sqlite3_shutdown
sqlite3_config_worker_threads 0
set t(0) singlethread
set t(1) multithread
set t(2) serialized
sqlite3_config $t($sqlite_options(threadsafe))
sqlite3_initialize
sqlite3_soft_heap_limit 0
reset_db
do_catchsql_test 16.1 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(1, NULL, 3);
INSERT INTO t1 VALUES(NULL, 2, 3);
INSERT INTO t1 VALUES(1, 2, NULL);
INSERT INTO t1 VALUES(4, 5, 6);
CREATE UNIQUE INDEX i1 ON t1(b, a, c);
} {0 {}}
reset_db
do_catchsql_test 16.2 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(1, NULL, 3);
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES(1, 2, NULL);
INSERT INTO t1 VALUES(4, 5, 6);
CREATE UNIQUE INDEX i1 ON t1(b, a, c);
} {1 {UNIQUE constraint failed: t1.b, t1.a, t1.c}}
reset_db
do_execsql_test 17.1 {
SELECT * FROM sqlite_master ORDER BY sql;
} {}
finish_test
+88
View File
@@ -0,0 +1,88 @@
# 2014 March 25.
#
# 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.
#
# Specifically, the tests in this file attempt to verify that
# multi-threaded sorting works.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sort2
foreach {tn script} {
1 { }
2 {
catch { db close }
sqlite3_shutdown
sqlite3_config_worker_threads 7
reset_db
}
} {
eval $script
do_execsql_test $tn.1 {
PRAGMA cache_size = 5;
WITH r(x,y) AS (
SELECT 1, randomblob(100)
UNION ALL
SELECT x+1, randomblob(100) FROM r
LIMIT 100000
)
SELECT count(x), length(y) FROM r GROUP BY (x%5)
} {
20000 100 20000 100 20000 100 20000 100 20000 100
}
do_execsql_test $tn.2.1 {
CREATE TABLE t1(a, b);
WITH r(x,y) AS (
SELECT 1, randomblob(100)
UNION ALL
SELECT x+1, randomblob(100) FROM r
LIMIT 10000
) INSERT INTO t1 SELECT * FROM r;
}
do_execsql_test $tn.2.2 {
CREATE UNIQUE INDEX i1 ON t1(b, a);
}
do_execsql_test $tn.2.3 {
CREATE UNIQUE INDEX i2 ON t1(a);
}
do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok}
breakpoint
do_execsql_test $tn.3 {
PRAGMA cache_size = 5;
WITH r(x,y) AS (
SELECT 1, randomblob(100)
UNION ALL
SELECT x+1, randomblob(100) FROM r
LIMIT 1000000
)
SELECT count(x), length(y) FROM r GROUP BY (x%5)
} {
200000 100 200000 100 200000 100 200000 100 200000 100
}
db close
sqlite3_shutdown
sqlite3_config_worker_threads 0
sqlite3_initialize
}
finish_test
+67
View File
@@ -0,0 +1,67 @@
# 2014 March 25.
#
# 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 tests in this file verify that sorting works when the library is
# configured to use mmap(), but the temporary files generated by the
# sorter are too large to be completely mapped.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sort3
# Sort roughly 20MB of data. Once with a mmap limit of 5MB and once without.
#
foreach {itest limit} {
1 5000000
2 0x7FFFFFFF
} {
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $limit
do_execsql_test 1.$itest {
WITH r(x,y) AS (
SELECT 1, randomblob(1000)
UNION ALL
SELECT x+1, randomblob(1000) FROM r
LIMIT 20000
)
SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5);
} {
4000 4000000
4000 4000000
4000 4000000
4000 4000000
4000 4000000
}
}
# Sort more than 2GB of data. At one point this was causing a problem.
# This test might take one minute or more to run.
#
do_execsql_test 2 {
PRAGMA cache_size = 20000;
WITH r(x,y) AS (
SELECT 1, randomblob(1000)
UNION ALL
SELECT x+1, randomblob(1000) FROM r
LIMIT 2200000
)
SELECT count(*), sum(length(y)) FROM r GROUP BY (x%5);
} {
440000 440000000
440000 440000000
440000 440000000
440000 440000000
440000 440000000
}
finish_test
+198
View File
@@ -0,0 +1,198 @@
# 2014 May 6.
#
# 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 tests in this file are brute force tests of the multi-threaded
# sorter.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sort4
# Configure the sorter to use 3 background threads.
catch { db close }
sqlite3_shutdown
sqlite3_config_worker_threads 3
sqlite3_initialize
reset_db
# Minimum number of seconds to run for. If the value is 0, each test
# is run exactly once. Otherwise, tests are repeated until the timeout
# expires.
set SORT4TIMEOUT 0
if {[permutation] == "multithread"} { set SORT4TIMEOUT 300 }
#--------------------------------------------------------------------
# Set up a table "t1" containing $nRow rows. Each row contains also
# contains blob fields that collectively contain at least $nPayload
# bytes of content. The table schema is as follows:
#
# CREATE TABLE t1(a INTEGER, <extra-columns>, b INTEGER);
#
# For each row, the values of columns "a" and "b" are set to the same
# pseudo-randomly selected integer. The "extra-columns", of which there
# are at most eight, are named c0, c1, c2 etc. Column c0 contains a 4
# byte string. Column c1 an 8 byte string. Field c2 16 bytes, and so on.
#
# This table is intended to be used for testing queries of the form:
#
# SELECT a, <cols>, b FROM t1 ORDER BY a;
#
# The test code checks that rows are returned in order, and that the
# values of "a" and "b" are the same for each row (the idea being that
# if field "b" at the end of the sorter record has not been corrupted,
# the rest of the record is probably Ok as well).
#
proc populate_table {nRow nPayload} {
set nCol 0
set n 0
for {set nCol 0} {$n < $nPayload} {incr nCol} {
incr n [expr (4 << $nCol)]
}
set cols [lrange [list xxx c0 c1 c2 c3 c4 c5 c6 c7] 1 $nCol]
set data [lrange [list xxx \
randomblob(4) randomblob(8) randomblob(16) randomblob(32) \
randomblob(64) randomblob(128) randomblob(256) randomblob(512) \
] 1 $nCol]
execsql { DROP TABLE IF EXISTS t1 }
db transaction {
execsql "CREATE TABLE t1(a, [join $cols ,], b);"
set insert "INSERT INTO t1 VALUES(:k, [join $data ,], :k)"
for {set i 0} {$i < $nRow} {incr i} {
set k [expr int(rand()*1000000000)]
execsql $insert
}
}
}
# Helper for [do_sorter_test]
#
proc sorter_test {nRow nRead nPayload} {
set res [list]
set nLoad [expr ($nRow > $nRead) ? $nRead : $nRow]
set nPayload [expr (($nPayload+3)/4) * 4]
set cols [list]
foreach {mask col} {
0x04 c0 0x08 c1 0x10 c2 0x20 c3
0x40 c4 0x80 c5 0x100 c6 0x200 c7
} {
if {$nPayload & $mask} { lappend cols $col }
}
# Create two SELECT statements. Statement $sql1 uses the sorter to sort
# $nRow records of a bit over $nPayload bytes each read from the "t1"
# table created by [populate_table] proc above. Rows are sorted in order
# of the integer field in each "t1" record.
#
# The second SQL statement sorts the same set of rows as the first, but
# uses a LIMIT clause, causing SQLite to use a temp table instead of the
# sorter for sorting.
#
set sql1 "SELECT a, [join $cols ,], b FROM t1 WHERE rowid<=$nRow ORDER BY a"
set sql2 "SELECT a FROM t1 WHERE rowid<=$nRow ORDER BY a LIMIT $nRead"
# Pass the two SQL statements to a helper command written in C. This
# command steps statement $sql1 $nRead times and compares the integer
# values in the rows returned with the results of executing $sql2. If
# the comparison fails (indicating some bug in the sorter), a Tcl
# exception is thrown.
#
sorter_test_sort4_helper db $sql1 $nRead $sql2
set {} {}
}
# Usage:
#
# do_sorter_test <testname> <args>...
#
# where <args> are any of the following switches:
#
# -rows N (number of rows to have sorter sort)
# -read N (number of rows to read out of sorter)
# -payload N (bytes of payload to read with each row)
# -cachesize N (Value for "PRAGMA cache_size = ?")
# -repeats N (number of times to repeat test)
# -fakeheap BOOL (true to use separate allocations for in-memory records)
#
proc do_sorter_test {tn args} {
set a(-rows) 1000
set a(-repeats) 1
set a(-read) 100
set a(-payload) 100
set a(-cachesize) 100
set a(-fakeheap) 0
foreach {s val} $args {
if {[info exists a($s)]==0} {
unset a(-cachesize)
set optlist "[join [array names a] ,] or -cachesize"
error "Unknown option $s, expected $optlist"
}
set a($s) $val
}
if {[permutation] == "memsys3" || [permutation] == "memsys5"} {
set a(-fakeheap) 0
}
if {$a(-fakeheap)} { sorter_test_fakeheap 1 }
db eval "PRAGMA cache_size = $a(-cachesize)"
do_test $tn [subst -nocommands {
for {set i 0} {[set i] < $a(-repeats)} {incr i} {
sorter_test $a(-rows) $a(-read) $a(-payload)
}
}] {}
if {$a(-fakeheap)} { sorter_test_fakeheap 0 }
}
proc clock_seconds {} {
db one {SELECT strftime('%s')}
}
#-------------------------------------------------------------------------
# Begin tests here.
# Create a test database.
do_test 1 {
execsql "PRAGMA page_size = 4096"
populate_table 100000 500
} {}
set iTimeLimit [expr [clock_seconds] + $SORT4TIMEOUT]
for {set t 2} {1} {incr tn} {
do_sorter_test $t.2 -repeats 10 -rows 1000 -read 100
do_sorter_test $t.3 -repeats 10 -rows 100000 -read 1000
do_sorter_test $t.4 -repeats 10 -rows 100000 -read 1000 -payload 500
do_sorter_test $t.5 -repeats 10 -rows 100000 -read 100000 -payload 8
do_sorter_test $t.6 -repeats 10 -rows 100000 -read 10 -payload 8
do_sorter_test $t.7 -repeats 10 -rows 10000 -read 10000 -payload 8 -fakeheap 1
do_sorter_test $t.8 -repeats 10 -rows 100000 -read 10000 -cachesize 250
set iNow [clock_seconds]
if {$iNow>=$iTimeLimit} break
do_test "$testprefix-([expr $iTimeLimit-$iNow] seconds remain)" {} {}
}
catch { db close }
sqlite3_shutdown
sqlite3_config_worker_threads 0
sqlite3_initialize
finish_test
+169
View File
@@ -0,0 +1,169 @@
# 2014 March 25.
#
# 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.
#
# Specifically, it tests the effects of fault injection on the sorter
# module (code in vdbesort.c).
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sortfault
do_execsql_test 1.0 {
PRAGMA cache_size = 5;
}
foreach {tn mmap_limit nWorker tmpstore threadsmode fakeheap lookaside} {
1 0 0 file multithread false false
2 100000 0 file multithread false false
3 100000 1 file multithread false false
4 2000000 0 file singlethread false true
} {
if {$sqlite_options(threadsafe)} { set threadsmode singlethread }
catch { db close }
sqlite3_shutdown
sqlite3_config_worker_threads $nWorker
sqlite3_config $threadsmode
if { $lookaside } {
sqlite3_config_lookaside 100 500
} else {
sqlite3_config_lookaside 0 0
}
sqlite3_initialize
sorter_test_fakeheap $fakeheap
set str [string repeat a 1000]
puts $threadsmode
do_faultsim_test 1.$tn -prep {
sqlite3 db test.db
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit
execsql { PRAGMA cache_size = 5 }
} -body {
execsql {
WITH r(x,y) AS (
SELECT 1, $::str
UNION ALL
SELECT x+1, $::str FROM r
LIMIT 200
)
SELECT count(x), length(y) FROM r GROUP BY (x%5)
}
} -test {
faultsim_test_result {0 {40 1000 40 1000 40 1000 40 1000 40 1000}}
}
do_faultsim_test 2.$tn -faults oom* -prep {
sqlite3 db test.db
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit
add_test_utf16bin_collate db
execsql { PRAGMA cache_size = 5 }
} -body {
execsql {
WITH r(x,y) AS (
SELECT 100, $::str
UNION ALL
SELECT x-1, $::str FROM r
LIMIT 100
)
SELECT count(x), length(y) FROM r GROUP BY y COLLATE utf16bin, (x%5)
}
} -test {
faultsim_test_result {0 {20 1000 20 1000 20 1000 20 1000 20 1000}}
}
if {$mmap_limit > 1000000} {
set str2 [string repeat $str 10]
sqlite3_memdebug_vfs_oom_test 0
sqlite3 db test.db
sqlite3_test_control SQLITE_TESTCTRL_SORTER_MMAP db $::mmap_limit
execsql { PRAGMA cache_size = 5 }
do_faultsim_test 3.$tn -faults oom-trans* -body {
execsql {
WITH r(x,y) AS (
SELECT 300, $::str2
UNION ALL
SELECT x-1, $::str2 FROM r
LIMIT 300
)
SELECT count(x), length(y) FROM r GROUP BY y, (x%5)
}
} -test {
faultsim_test_result {0 {60 10000 60 10000 60 10000 60 10000 60 10000}}
}
sqlite3_memdebug_vfs_oom_test 1
}
}
catch { db close }
sqlite3_shutdown
sqlite3_config_worker_threads 0
set t(0) singlethread
set t(1) multithread
set t(2) serialized
sqlite3_config $t($sqlite_options(threadsafe))
sqlite3_config_lookaside 100 500
sqlite3_initialize
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 4.0 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
}
do_test 4.1 {
for {set i 0} {$i < 256} {incr i} {
execsql {
INSERT INTO t1 SELECT
((a<<3) + b) & 2147483647,
((b<<3) + c) & 2147483647,
((c<<3) + a) & 2147483647
FROM t1 ORDER BY rowid DESC LIMIT 1;
}
}
} {}
faultsim_save_and_close
do_faultsim_test 4.2 -faults oom* -prep {
faultsim_restore_and_reopen
} -body {
execsql { CREATE UNIQUE INDEX i1 ON t1(a,b,c) }
} -test {
faultsim_test_result {0 {}}
}
#-------------------------------------------------------------------------
#
reset_db
set a [string repeat a 500]
set b [string repeat b 500]
set c [string repeat c 500]
do_execsql_test 5.0 {
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES($a, $b, $c);
INSERT INTO t1 VALUES($c, $b, $a);
}
do_faultsim_test 5.1 -faults oom* -body {
execsql { SELECT * FROM t1 ORDER BY a }
} -test {
faultsim_test_result [list 0 [list $::a $::b $::c $::c $::b $::a]]
}
finish_test
+195 -1
View File
@@ -27,8 +27,10 @@ static const char zHelp[] =
" --stats Show statistics at the end\n"
" --testset T Run test-set T\n"
" --trace Turn on SQL tracing\n"
" --threads N Use up to N threads for sorting\n"
" --utf16be Set text encoding to UTF-16BE\n"
" --utf16le Set text encoding to UTF-16LE\n"
" --verify Run additional verification steps.\n"
" --without-rowid Use WITHOUT ROWID where appropriate\n"
;
@@ -51,6 +53,7 @@ static struct Global {
int bReprepare; /* True to reprepare the SQL on each rerun */
int bSqlOnly; /* True to print the SQL once only */
int bExplain; /* Print SQL with EXPLAIN prefix */
int bVerify; /* Try to verify that results are correct */
int szTest; /* Scale factor for test iterations */
const char *zWR; /* Might be WITHOUT ROWID */
const char *zNN; /* Might be NOT NULL */
@@ -931,6 +934,183 @@ void testset_cte(void){
}
/* Generate two numbers between 1 and mx. The first number is less than
** the second. Usually the numbers are near each other but can sometimes
** be far apart.
*/
static void twoCoords(
int p1, int p2, /* Parameters adjusting sizes */
unsigned mx, /* Range of 1..mx */
unsigned *pX0, unsigned *pX1 /* OUT: write results here */
){
unsigned d, x0, x1, span;
span = mx/100 + 1;
if( speedtest1_random()%3==0 ) span *= p1;
if( speedtest1_random()%p2==0 ) span = mx/2;
d = speedtest1_random()%span + 1;
x0 = speedtest1_random()%(mx-d) + 1;
x1 = x0 + d;
*pX0 = x0;
*pX1 = x1;
}
/* The following routine is an R-Tree geometry callback. It returns
** true if the object overlaps a slice on the Y coordinate between the
** two values given as arguments. In other words
**
** SELECT count(*) FROM rt1 WHERE id MATCH xslice(10,20);
**
** Is the same as saying:
**
** SELECT count(*) FROM rt1 WHERE y1>=10 AND y0<=20;
*/
static int xsliceGeometryCallback(
sqlite3_rtree_geometry *p,
int nCoord,
double *aCoord,
int *pRes
){
*pRes = aCoord[3]>=p->aParam[0] && aCoord[2]<=p->aParam[1];
return SQLITE_OK;
}
/*
** A testset for the R-Tree virtual table
*/
void testset_rtree(int p1, int p2){
unsigned i, n;
unsigned mxCoord;
unsigned x0, x1, y0, y1, z0, z1;
unsigned iStep;
int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*100 );
mxCoord = 15000;
n = g.szTest*100;
speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
speedtest1_exec("BEGIN");
speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
speedtest1_prepare("INSERT INTO rt1(id,x0,x1,y0,y1,z0,z1)"
"VALUES(?1,?2,?3,?4,?5,?6,?7)");
for(i=1; i<=n; i++){
twoCoords(p1, p2, mxCoord, &x0, &x1);
twoCoords(p1, p2, mxCoord, &y0, &y1);
twoCoords(p1, p2, mxCoord, &z0, &z1);
sqlite3_bind_int(g.pStmt, 1, i);
sqlite3_bind_int(g.pStmt, 2, x0);
sqlite3_bind_int(g.pStmt, 3, x1);
sqlite3_bind_int(g.pStmt, 4, y0);
sqlite3_bind_int(g.pStmt, 5, y1);
sqlite3_bind_int(g.pStmt, 6, z0);
sqlite3_bind_int(g.pStmt, 7, z1);
speedtest1_run();
}
speedtest1_exec("COMMIT");
speedtest1_end_test();
speedtest1_begin_test(101, "Copy from rtree to a regular table");
speedtest1_exec("CREATE TABLE t1(id INTEGER PRIMARY KEY,x0,x1,y0,y1,z0,z1)");
speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
speedtest1_end_test();
n = g.szTest*20;
speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
aCheck[i] = atoi(g.zResult);
}
speedtest1_end_test();
if( g.bVerify ){
n = g.szTest*20;
speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
if( aCheck[i]!=atoi(g.zResult) ){
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
}
}
speedtest1_end_test();
}
n = g.szTest*20;
speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
aCheck[i] = atoi(g.zResult);
}
speedtest1_end_test();
if( g.bVerify ){
n = g.szTest*20;
speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
if( aCheck[i]!=atoi(g.zResult) ){
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
}
}
speedtest1_end_test();
}
n = g.szTest*20;
speedtest1_begin_test(125, "%d custom geometry callback queries", n);
sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
if( aCheck[i]!=atoi(g.zResult) ){
fatal_error("Count disagree step %d: %d..%d. %d vs %d",
i, i*iStep, (i+1)*iStep, aCheck[i], atoi(g.zResult));
}
}
speedtest1_end_test();
n = g.szTest*80;
speedtest1_begin_test(130, "%d three-dimensional intersect box queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x1>=?1 AND x0<=?2"
" AND y1>=?1 AND y0<=?2 AND z1>=?1 AND z0<=?2");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
sqlite3_bind_int(g.pStmt, 2, (i+1)*iStep);
speedtest1_run();
aCheck[i] = atoi(g.zResult);
}
speedtest1_end_test();
n = g.szTest*100;
speedtest1_begin_test(140, "%d rowid queries", n);
speedtest1_prepare("SELECT * FROM rt1 WHERE id=?1");
for(i=1; i<=n; i++){
sqlite3_bind_int(g.pStmt, 1, i);
speedtest1_run();
}
speedtest1_end_test();
}
/*
** A testset used for debugging speedtest1 itself.
*/
@@ -962,6 +1142,7 @@ int main(int argc, char **argv){
int nPCache = 0, szPCache = 0;/* --pcache configuration */
int nScratch = 0, szScratch=0;/* --scratch configuration */
int showStats = 0; /* True for --stats */
int nThread = 0; /* --threads value */
const char *zTSet = "main"; /* Which --testset torun */
int doTrace = 0; /* True for --trace */
const char *zEncoding = 0; /* --utf16be or --utf16le */
@@ -1046,10 +1227,15 @@ int main(int argc, char **argv){
zTSet = argv[++i];
}else if( strcmp(z,"trace")==0 ){
doTrace = 1;
}else if( strcmp(z,"threads")==0 ){
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
nThread = integerValue(argv[++i]);
}else if( strcmp(z,"utf16le")==0 ){
zEncoding = "utf16le";
}else if( strcmp(z,"utf16be")==0 ){
zEncoding = "utf16be";
}else if( strcmp(z,"verify")==0 ){
g.bVerify = 1;
}else if( strcmp(z,"without-rowid")==0 ){
g.zWR = "WITHOUT ROWID";
g.zPK = "PRIMARY KEY";
@@ -1092,6 +1278,11 @@ int main(int argc, char **argv){
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch);
if( rc ) fatal_error("scratch configuration failed: %d\n", rc);
}
#ifdef SQLITE_CONFIG_WORKER_THREADS
if( nThread>0 ){
sqlite3_config(SQLITE_CONFIG_WORKER_THREADS, nThread);
}
#endif
if( nLook>0 ){
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
}
@@ -1141,8 +1332,11 @@ int main(int argc, char **argv){
testset_debug1();
}else if( strcmp(zTSet,"cte")==0 ){
testset_cte();
}else if( strcmp(zTSet,"rtree")==0 ){
testset_rtree(6, 147);
}else{
fatal_error("unknown testset: \"%s\"\n", zTSet);
fatal_error("unknown testset: \"%s\"\nChoices: main debug1 cte rtree\n",
zTSet);
}
speedtest1_final();
+2
View File
@@ -1076,6 +1076,7 @@ proc explain_i {sql {db db}} {
foreach opcode {
Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind
NoConflict Next Prev VNext VPrev VFilter
SorterSort SorterNext
} {
set color($opcode) $B
}
@@ -1098,6 +1099,7 @@ proc explain_i {sql {db db}} {
if {$opcode=="Next" || $opcode=="Prev"
|| $opcode=="VNext" || $opcode=="VPrev"
|| $opcode=="SorterNext"
} {
for {set i $p2} {$i<$addr} {incr i} {
incr x($i) 2
+53
View File
@@ -0,0 +1,53 @@
# 2014 April 26
#
# 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.
#
#***********************************************************************
# Test that ticket f67b41381a has been resolved.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-f67b41381a
do_execsql_test 1.0 {
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1);
ALTER TABLE t1 ADD COLUMN b DEFAULT 2;
CREATE TABLE t2(a, b);
INSERT INTO t2 SELECT * FROM t1;
SELECT * FROM t2;
} {1 2}
db cache size 0
foreach {tn tbls xfer} {
1 { CREATE TABLE t1(a, b); CREATE TABLE t2(a, b) } 1
2 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b) } 0
3 { CREATE TABLE t1(a, b DEFAULT 'x'); CREATE TABLE t2(a, b DEFAULT 'x') } 1
4 { CREATE TABLE t1(a, b DEFAULT NULL); CREATE TABLE t2(a, b) } 0
5 { CREATE TABLE t1(a DEFAULT 2, b); CREATE TABLE t2(a DEFAULT 1, b) } 1
6 { CREATE TABLE t1(a DEFAULT 1, b); CREATE TABLE t2(a DEFAULT 1, b) } 1
7 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1);
CREATE TABLE t2(a DEFAULT 3, b DEFAULT 1) } 1
8 { CREATE TABLE t1(a DEFAULT 1, b DEFAULT 1);
CREATE TABLE t2(a DEFAULT 3, b DEFAULT 3) } 0
} {
execsql { DROP TABLE t1; DROP TABLE t2 }
execsql $tbls
set res 1
db eval { EXPLAIN INSERT INTO t1 SELECT * FROM t2 } {
if {$opcode == "Column"} { set res 0 }
}
do_test 2.$tn [list set res] $xfer
}
finish_test
+1 -1
View File
@@ -42,7 +42,7 @@ foreach idxmode {ordered unordered} {
1 "SELECT * FROM t1 ORDER BY a"
{0 0 0 {SCAN TABLE t1 USING INDEX i1}}
{0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}}
2 "SELECT * FROM t1 WHERE a >?"
2 "SELECT * FROM t1 WHERE a > 100"
{0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
{0 0 0 {SCAN TABLE t1}}
3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
+7 -1
View File
@@ -811,7 +811,13 @@ do_test wal2-7.1.1 {
do_test wal2-7.1.2 {
forcecopy test.db test2.db
forcecopy test.db-wal test2.db-wal
hexio_write test2.db-wal 48 FF
# The first 32 bytes of the WAL file contain the WAL header. Offset 48
# is the first byte of the checksum for the first frame in the WAL.
# The following three lines replaces the contents of that byte with
# a different value.
set newval FF
if {$newval == [hexio_read test2.db-wal 48 1]} { set newval 00 }
hexio_write test2.db-wal 48 $newval
} {1}
do_test wal2-7.1.3 {
sqlite3 db2 test2.db
+2 -1
View File
@@ -231,6 +231,7 @@ do_execsql_test where3-3.0 {
CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c);
CREATE INDEX t301c ON t301(c);
INSERT INTO t301 VALUES(1,2,3);
INSERT INTO t301 VALUES(2,2,3);
CREATE TABLE t302(x, y);
INSERT INTO t302 VALUES(4,5);
ANALYZE;
@@ -251,7 +252,7 @@ do_execsql_test where3-3.2 {
} {}
do_execsql_test where3-3.3 {
SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL;
} {1 2 3}
} {1 2 3 2 2 3}
if 0 { # Query planner no longer does this
# Verify that when there are multiple tables in a join which must be
+42
View File
@@ -14,6 +14,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix whereG
do_execsql_test whereG-1.0 {
CREATE TABLE composer(
@@ -179,5 +180,46 @@ do_execsql_test whereG-4.0 {
ORDER BY x;
} {right}
#-------------------------------------------------------------------------
# Test that likelihood() specifications on indexed terms are taken into
# account by various forms of loops.
#
# 5.1.*: open ended range scans
# 5.2.*: skip-scans
#
reset_db
do_execsql_test 5.1 {
CREATE TABLE t1(a, b, c);
CREATE INDEX i1 ON t1(a, b);
}
do_eqp_test 5.1.2 {
SELECT * FROM t1 WHERE a>?
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
do_eqp_test 5.1.3 {
SELECT * FROM t1 WHERE likelihood(a>?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
do_test 5.2 {
for {set i 0} {$i < 100} {incr i} {
execsql { INSERT INTO t1 VALUES('abc', $i, $i); }
}
execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; }
execsql { ANALYZE }
} {}
do_eqp_test 5.2.2 {
SELECT * FROM t1 WHERE likelihood(b>?, 0.01)
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}}
do_eqp_test 5.2.3 {
SELECT * FROM t1 WHERE likelihood(b>?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
do_eqp_test 5.3.1 {
SELECT * FROM t1 WHERE a=?
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
do_eqp_test 5.3.2 {
SELECT * FROM t1 WHERE likelihood(a=?, 0.9)
} {0 0 0 {SCAN TABLE t1}}
finish_test
+5 -2
View File
@@ -83,7 +83,8 @@ static LogEst logEstFromDouble(double x){
LogEst e;
assert( sizeof(x)==8 && sizeof(a)==8 );
if( x<=0.0 ) return -32768;
if( x<1.0 ) return -logEstFromDouble(1/x);
if( x<0.01 ) return -logEstFromDouble(1.0/x);
if( x<1.0 ) return logEstFromDouble(100.0*x) - 66;
if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
memcpy(&a, &x, 8);
@@ -156,8 +157,10 @@ int main(int argc, char **argv){
}
}
for(i=n-1; i>=0; i--){
if( a[i]<0 ){
if( a[i]<-40 ){
printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
}else if( a[i]<10 ){
printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0);
}else{
sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
+1
View File
@@ -237,6 +237,7 @@ foreach file {
malloc.c
printf.c
random.c
threads.c
utf.c
util.c
hash.c
+1
View File
@@ -249,6 +249,7 @@ foreach file {
malloc.c
printf.c
random.c
threads.c
utf.c
util.c
hash.c