Compare commits

...

115 Commits

Author SHA1 Message Date
dan 6d52725e87 Experimental multi-threaded sorting changes to begin merging PMAs before SorterRewind() is called.
FossilOrigin-Name: cbfc0f6d49b6607bb4eb45bfe4c258e39ac27403
2014-04-07 18:44:00 +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
drh 853546d047 Merge changes to the query planner that strive to ensure that any index
usage that is a proper subset of some other index usage always has a slightly
higher cost.

FossilOrigin-Name: 683dd379a293b2f330e1e4cd746f190527fe48ee
2014-04-04 18:20:35 +00:00
drh 1fb6a11072 Ensure the "PRAGMA journal_mode=WAL" works coming from any other journal_mode
with ATTACH-ed databases.

FossilOrigin-Name: e54330b43127e46fc6494748cbb353a6fc91cfd7
2014-04-04 14:12:52 +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
drh c438df1be0 Use OP_Copy instead of OP_SCopy when moving results out of a subquery,
to prevent the subquery results from changing out from under the outer
query.  Fix for ticket [1e64dd782a126f48d78].

FossilOrigin-Name: d5513dfa23baa0b0a095aaf17d19aacd30dcef61
2014-04-03 16:29:31 +00:00
dan 8930c2ab0c Fix an integer overflow problem in the sorter.
FossilOrigin-Name: 9d3351b8d713232133dad149c73fb2a27c72abb1
2014-04-03 16:25:29 +00:00
drh 831116d164 Fix a typo in the "Synopsis:" comment for the OP_VFilter opcode.
FossilOrigin-Name: 48ecdd4aff03741f96c070dced69c3c273b652cb
2014-04-03 14:31:00 +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 54d0d2dd9a In the command-line shell, run set writable_schema before running the
".clone" command.

FossilOrigin-Name: 9d2ae6342c8afa904bec591ebe134ff7f536b71c
2014-04-03 00:32:13 +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
drh d3c156638a Remove an unnecessary conditional.
FossilOrigin-Name: 7473c4dfc10a47594affa6f4e071a08dc8838c0c
2014-03-31 20:05:20 +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
drh 3fb183d2f7 Also make sure an index that is a proper subset of some other index has a
higher cost than that other index.  Add test cases.

FossilOrigin-Name: b7830d232b073a197aa1092e78cb24e88cb10fd3
2014-03-31 19:49:00 +00:00
drh 53cd10afcd Make sure that an index that covers a proper superset of the WHERE clause
terms of some other index has a lower cost than the other index.

FossilOrigin-Name: ea8b0910040198751551b0b960e6b783913607df
2014-03-31 18:24:18 +00:00
drh b663587890 Avoid a (harmless) buffer overread that is possible on an OOM when
MEMSYS5 is engaged.

FossilOrigin-Name: b3296267fb67b9f59719a37093253062edde3746
2014-03-31 13:42:42 +00:00
drh 7a4b1642a7 Experiments in picking better query plans, especially when the usage of one
index is a subset of another.

FossilOrigin-Name: 8f869ca7a6eaa9ca7a08102290e6c606735f9090
2014-03-29 21:16:07 +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
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
drh 70c93204ea Disable the wal64k.test script for non-unix systems since it depends on
unix-only features.

FossilOrigin-Name: 27deb6e49bcc76714dbdc61b34748603155ac770
2014-03-28 14:41:35 +00:00
drh 36ed03428d Fix a harmless compiler warning.
FossilOrigin-Name: a4e47150f32b3a4120b1f89ccc66d633d829e3bb
2014-03-28 12:56:57 +00:00
drh a1f7c0a21c Enhance the sqlite3VdbeRecordCompare() routines so that if they encounter
database corruption, they will set the UnpackedRecord.isCorrupt field and
return 0.  The sqlite3BtreeMovetoUnpacked() routine detects this and returns
SQLITE_CORRUPT, causing the corruption to be reported back to the top-level.

FossilOrigin-Name: 7fa85eaaaf6d211378620d728a759fdfe30a15b0
2014-03-28 03:12:48 +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
drh 27de5c5cb6 Minor cleanup of the code in the query planner that computes the costs
estimates for the various plans.  There are no changes to the costs at this
time.  But the code is slightly more readable now and that might facilitate
future enhancements.

FossilOrigin-Name: 9b4d7226bcee38be5ac68a54bee03b4179cb69fc
2014-03-27 18:36:34 +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 382bdeabef Enhance the logest.c utility with new operators: "dup", "inv", "log", and
"nlogn".  Provide help on an invalid input.

FossilOrigin-Name: b4bd2a062c4baf5f622d61b7411f00de5904ef56
2014-03-27 14:05:38 +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
dan 68916c9fd3 Add an extra test case for the potential buffer overread patched by [28ddecff04].
FossilOrigin-Name: f585f5d7a0f9bf8c590388654a3638231eba8892
2014-03-26 15:14:59 +00:00
drh d9c131c366 Add a test case to verify that the previous change avoids excess buffer
overread in sqlite3VdbeRecordCompare().

FossilOrigin-Name: 2b28e8d582cf10936fa1faca04a16ca2eeead66f
2014-03-26 15:05:56 +00:00
drh 182ea4e324 Earlier detection of corruption in sqlite3VdbeRecordCompare() in order to
avoid a potential buffer overread.

FossilOrigin-Name: 28ddecff044dbc2dff50a7d8406ab67dfe06587f
2014-03-26 14:51:07 +00:00
drh e2ac506704 Add an assert() and a comment to clarify the operation of the
vdbeRecordCompareInt() routine.

FossilOrigin-Name: 851abdb8fd9b5a8a6ce21db53d30dbac3c430cc7
2014-03-26 12:02:38 +00:00
drh 5e8980ddb1 Adjust the repeat counts on several tests in speedtest1 so that the relative
time spent on the test is roughly the same regardless of --size.

FossilOrigin-Name: 7922809ee0d3978ce9221fbb7df63aa0684d0c4d
2014-03-25 20:28:38 +00:00
drh e6c7b09df6 Merge enhancements and fixes from trunk.
FossilOrigin-Name: e005f2d6dd9faf38cc8fdb9428b5aa6192a6adae
2014-03-25 18:29:12 +00:00
drh c872966ef4 Add another performance test case to speedtest1. This case is another
ORDER BY test but this time without LIMIT.

FossilOrigin-Name: 9ab7ffd59209aef0ffbf384b3902a93fd3b86a6d
2014-03-25 17:45:49 +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 0c60c1fe66 Add an ORDER BY test case to speedtest1.c
FossilOrigin-Name: 588122641e57e957813d329ea071e13ccbde5acd
2014-03-25 14:54:36 +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
drh 86dd3716b9 Detect when a VdbeCursor is still pointing at a valid row but that row has
moved, and invalidated the return from prior sqlite3BtreeDataFetch() or
sqlite3BtreeKeyFetch() calls.

FossilOrigin-Name: e6798871ce94961135762669af418cd78540c121
2014-03-25 11:00:21 +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 b22f38a779 Remove unused variables Parse.nColCache and Parse.iColCache.
FossilOrigin-Name: 4d7551ce464c8038147e81667368924f2a7485a6
2014-03-24 16:30:06 +00:00
drh 3d1d90a13d Fix arithmetic operators so that they do not change the affinity of their
input operands.  Ticket [a8a0d2996a].

FossilOrigin-Name: 221f8f944703108e47d789fa8ce6c00fe2abcbb6
2014-03-24 15:00:15 +00:00
dan 4979088506 Avoid attempting to mmap memory from an offset that is not a multiple of the system page size on systems with page sizes larger than 32KB.
FossilOrigin-Name: db7d62c8d58eb1e8654a762c9b199ae4e2759038
2014-03-24 11:23:17 +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
drh 323913c880 Avoid a possible use of an uninitialized variable following an I/O or OOM
error.

FossilOrigin-Name: 641408a1395bfc911ca619ef9e5f073b913d856b
2014-03-23 16:29:23 +00:00
drh dbfca2b7f8 Clear the sort-order flags on the KeyInfo object associated with the
OP_Compare/OP_Jump of the block-sort logic, in order to make the OP_Jump
fully testable.

FossilOrigin-Name: 9b2838f23e5f52369eeb078f60bd231cc54362f8
2014-03-22 02:19:53 +00:00
drh c83a6bed04 Increase the version number to 3.8.5.
FossilOrigin-Name: 9760879d086b61476890927f01806a93798d4eee
2014-03-22 01:52:17 +00:00
drh 59b8f2e108 Fix the ORDER BY optimization logic so that it will do a block-sort on
a partial DESC ORDER BY.  This enhancement uncovered a memory leak in
pushUntoSorter() which is also fixed.

FossilOrigin-Name: c36f74611cf17ad2ff198a2ac2054d7ab451a72c
2014-03-22 00:27:14 +00:00
drh 9a4444778f Add the ability to use indices for the first few terms of an ORDER BY clause,
then sort in batches to handle the later terms.

FossilOrigin-Name: fa06a6fed9f48322d9b89721799ba12c46efa898
2014-03-21 20:58:42 +00:00
drh 8e1ee88c88 Change the names of SRT_DistTable and SRT_Table used by CTE to more
meaningful SRT_DistFifo and SRT_Fifo, respectively.  Simplify the
IgnorableOrderby() macro in the process.

FossilOrigin-Name: 45d8cc678d128f1dda6469864215a8ed9de4366a
2014-03-21 19:56:09 +00:00
dan 9afccba269 Avoid leaking memory in an obscure case where the flattener adds an ORDER BY clause to the recursive part of a recursive query.
FossilOrigin-Name: 1f413aca00015100224273480e1ce39a76bf93ab
2014-03-21 19:27:54 +00:00
drh cc08fa48b8 Merge the OFFSET-on-query-without-FROM fix from trunk.
FossilOrigin-Name: 71e9ae72c272dc86720b2bfe719f57de437c400b
2014-03-21 18:45:19 +00:00
drh a22a75e5ca Fix the OFFSET clause so that it works correctly on queries that lack
a FROM clause.  Ticket [07d6a0453d4ed8].

FossilOrigin-Name: 179ef81648b0ad557df78b7712f216b876b6fb65
2014-03-21 18:16:23 +00:00
drh e99b9cdc70 New test case for block-sorting.
FossilOrigin-Name: e70cfa28aa393661ccc742ecd5e672d807bdd0a9
2014-03-21 15:24:07 +00:00
drh f9f1bdb0c8 Merge trunk fixes for "x IN (?)" handling.
FossilOrigin-Name: eca35871c34374ca9189c7c9b6d490ac3c30357f
2014-03-20 20:56:49 +00:00
drh 5b1420e046 Remove a testcase() that is now always true due to the "x IN (?)" optimization.
Add an ALWAYS() around a conditional in the parser that cannot be false.

FossilOrigin-Name: d5a1530bdc7ace053d05d1a037551110021d3758
2014-03-20 19:04:56 +00:00
drh 8ad0de3f72 Fix the EXPLAIN indenter in the command-line shell to correctly
handle NextIfOpen and PrevIfOpen opcodes.

FossilOrigin-Name: 01944c53f5c129f48ce8842faaedcf5607dd381e
2014-03-20 18:45:27 +00:00
drh fbb24d1092 The "x IN (?)" optimization in check-ins [2ff3b25f40] and [e68b427afb] is
incorrect, as demonstrated by the in4-5.1 test case in this check-in.
The "COLLATE binary" that was being added to the RHS of IN was overriding
the implicit collating sequence of the LHS.  This change defines the EP_Generic
expression node property that blocks all affinity or collating sequence
information in the expression subtree and adds that property to the expression
taken from RHS of the IN operator.

FossilOrigin-Name: 2ea4a9f75f46eaa928ba17e9e91bc0432750d46d
2014-03-20 17:03:30 +00:00
drh 4ef7efad5e Fix harmless compiler warnings.
FossilOrigin-Name: b1435f26b07b2208cfcca557f96342a5bd0d5328
2014-03-20 15:14:08 +00:00
drh 0a8d14261c Previous check-in is not quite correct. "x IN (?)" is not exactly the same
as "x==?" do to collation and affinity issues.  The correct converstion should
be to "x==(+? COLLATE binary)".  The current check-in fixes this problem and
provides test cases.  Ticket [e39d032577df69]

FossilOrigin-Name: 2ff3b25f40fd117c8a2da1d1a3625f6b167b7b16
2014-03-20 14:56:47 +00:00
drh 2b59b3a4c8 Convert expressions of the form "X IN (?)" with exactly one value on the
RHS of the IN into equality tests:  "X=?".  Add test cases to verify that
statements work correctly on this corner case.
Fix for ticket [e39d032577df6942].

FossilOrigin-Name: e68b427afbc82e201c64474117851aa4c9eb0c92
2014-03-20 13:26:47 +00:00
drh 0c8a934cb4 Fix an unnecessarily obtuse use of a bitmask flag.
FossilOrigin-Name: ca3140813198ab7ce470cf86334e55207f3461f9
2014-03-20 12:17:35 +00:00
dan bc76063cd2 Add a test to ensure os_unix.c works with 64KiB OS pages.
FossilOrigin-Name: e3d2be3ba47cdaafd26347620ae3bc2813203f16
2014-03-20 09:42:09 +00:00
dan 781e34cde3 Add an experimental fix to avoid attempting to mmap memory from an offset that is not a multiple of the system page size on systems with page sizes larger than 32KB.
FossilOrigin-Name: 6f3a5c24d254fc6faf607b505bdef4a7aafc21af
2014-03-20 08:59:47 +00:00
drh db1cc09c72 Merge the vdbesort.c optimization from trunk.
FossilOrigin-Name: e4bfffb988283c077778c60696be0d285ad66c3c
2014-03-19 23:42:51 +00:00
drh 6284db908a Fix query planner weights associated with choosing block-sorting. Fix
block sorting of tables with collating functions.  Fix various test cases.
All "veryquick" tests are now passing, though more tests need to be added.

FossilOrigin-Name: 01afbf97c0ff29667806e9a7c4d74ca717819de5
2014-03-19 23:24:49 +00:00
dan 344510e62b Avoid some unnecessary calls to sqlite3VdbeRecordUnpack() that were being made when merging data from two or more temp files together in vdbesort.c
FossilOrigin-Name: 707ea170b3e26965b7e3982f7554d122d130b9a6
2014-03-19 20:01:25 +00:00
drh 65ea12cb4a Make it possible for block-sort to use the OP_SorterOpen sorter in addition
to a generic OP_OpenEphemeral.

FossilOrigin-Name: 7ce2daafd39a117041bfdd0a7132e2764fe7a74b
2014-03-19 17:41:36 +00:00
drh 26d7e7c6b7 Fix a problem in the block-sort logic that can arise if the VDBE opcode
array is resized while the block-sort logic is being coded.  "make test"
now runs to completion, though there are still 17 failures.

FossilOrigin-Name: 62f3a22050e0f11c789374f8a3785df0a84c24cb
2014-03-19 16:56:58 +00:00
drh ba194369ad Avoid reusing temporary registers in co-routines when doing
block-sorting.

FossilOrigin-Name: 463d921b519b08648a715e987c430f06b06bae84
2014-03-19 15:17:24 +00:00
drh ea6c36e204 Make sure the where.c query planner never reports that the number of ORDER BY
terms that are satisfied by indices is negative.

FossilOrigin-Name: b186d8d15a10d5e8fcae9ae72e8624d71831f5bd
2014-03-19 14:30:55 +00:00
drh 079a307259 First attempt at getting block-sort to work. This is an incremental check-in.
There are many problems still to be worked out.

FossilOrigin-Name: 59742dd4c5259883850044d0938248b009ebd045
2014-03-19 14:10:55 +00:00
drh ddba0c227e Make the partial-ORDER-BY information in the query planner available to the
SELECT code generator.  Still doesn't make a difference in the generated code.

FossilOrigin-Name: e258df236b7de70087c8227cb209080e55b9bf9c
2014-03-18 20:33:42 +00:00
drh d2de861cbe Adjust the query planner to keep track of the number of ORDER BY terms
satisfied.  Still doesn't do anything with this information.  Some tests
fail after this check-in, but all failures are believed to be benign.  The
failures will be addressed at a later stage.

FossilOrigin-Name: 59d49b7fc49fa290e04a02653e7268c85836b27e
2014-03-18 18:59:07 +00:00
drh 0401acec91 Experiments with the optimization of ORDER BY and GROUP BY clauses.
FossilOrigin-Name: b150902579d708b454efd5f8750e26a816f7f1a6
2014-03-18 15:30:27 +00:00
dan f87684189d Add an experimental multi-threaded capability to vdbesorter.c.
FossilOrigin-Name: ff0b5c851ba7d04d1836d7c6a3222713e7d8d357
2014-03-17 15:43:05 +00:00
drh 0e682099a1 Clean up some obsolete "register" declarations in printf.c.
FossilOrigin-Name: ecd9d3f9453be0bb8e312d8027fd1a9e55882f36
2014-03-17 15:06:57 +00:00
drh a70a073b3f Performance enhancements and size reduction for sqlite3VXPrintf()
FossilOrigin-Name: eb071eb58cf675bd6cd9dd46aed9d57fbb7a77e8
2014-03-17 14:24:27 +00:00
drh 18c7e40ca3 Fix a harmless compiler warning that crops up with SQLITE_MAX_MMAP_SIZE=0.
FossilOrigin-Name: 1277932b7e8bb36c7070ffafbf110a8e128c267b
2014-03-14 11:46:10 +00:00
dan c625ba7f4f Merge latest trunk changes into this branch.
FossilOrigin-Name: d17231b63d48c1f9c4dee109c90cec112e2f0fd4
2014-03-13 15:41:09 +00:00
dan d88e521f59 Fix an obscure bug causing sqlite3_close() to fail if there are virtual tables on the disconnect list when it is called.
FossilOrigin-Name: 6504aa47a8ebb13827be017c4cb4b2dc3c4c55f4
2014-03-12 19:38:38 +00:00
dan 82d25da5b0 Changes to FTS to ensure that it does not access the database from within the xConnect method.
FossilOrigin-Name: c67a52c356416cc200f51f9168d942e78db11d34
2014-03-12 19:20:36 +00:00
dan 87af14a639 Prevent the rtree module from reading sqlite_stat1 data from the wrong database.
FossilOrigin-Name: 7ce03c1b5552d830300575c5b41a874db7a2ec77
2014-03-12 12:44:46 +00:00
drh 468108628c Version 3.8.4.1
FossilOrigin-Name: 018d317b1257ce68a92908b05c9c7cf1494050d0
2014-03-11 15:27:36 +00:00
drh 8073c70b33 Update version number to 3.8.4.1
FossilOrigin-Name: 33f5694fa42d9a521ca081de4ddd1e9dc8952b16
2014-03-11 15:25:43 +00:00
dan 3afca7d18c Add a test to see what happens if an rtree constructor encounters an SQLITE_BUSY error. No changes to code.
FossilOrigin-Name: 5527e23636eee192030f6a3c41628030b6c50bb8
2014-03-11 09:19:26 +00:00
drh 89212fb9f9 Adjustments to the cost computation for the skip-scan query plan, to take
into account the fact that a seek has to occur on each skip.

FossilOrigin-Name: 0769eebd028ce31375cf93509a1d3687f7b117eb
2014-03-10 20:12:31 +00:00
drh b06a4ec1f0 Attempt to work around MSVC's treatment of __LINE__ as a non-constant value
in "Edit and Continue" mode by avoiding the use of __LINE__ when
SQLITE_VDBE_COVERAGE is not defined.

FossilOrigin-Name: 0a5318bc272b844e937cb1df3a07224034bc3450
2014-03-10 18:03: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 4064 additions and 1071 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.o 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
+1 -1
View File
@@ -1 +1 @@
3.8.4
3.8.5
Vendored
+9 -9
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.4.
# Generated by GNU Autoconf 2.62 for sqlite 3.8.5.
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.8.4'
PACKAGE_STRING='sqlite 3.8.4'
PACKAGE_VERSION='3.8.5'
PACKAGE_STRING='sqlite 3.8.5'
PACKAGE_BUGREPORT=''
# Factoring default headers for most tests.
@@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.8.4 to adapt to many kinds of systems.
\`configure' configures sqlite 3.8.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1548,7 +1548,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.8.4:";;
short | recursive ) echo "Configuration of sqlite 3.8.5:";;
esac
cat <<\_ACEOF
@@ -1664,7 +1664,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.8.4
sqlite configure 3.8.5
generated by GNU Autoconf 2.62
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.8.4, which was
It was created by sqlite $as_me 3.8.5, which was
generated by GNU Autoconf 2.62. Invocation command line was
$ $0 $@
@@ -14021,7 +14021,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.8.4, which was
This file was extended by sqlite $as_me 3.8.5, which was
generated by GNU Autoconf 2.62. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -14074,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
sqlite config.status 3.8.4
sqlite config.status 3.8.5
configured by $0, generated by GNU Autoconf 2.62,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+37 -7
View File
@@ -1410,10 +1410,7 @@ static int fts3InitVtab(
** addition of a %_stat table so that it can use incremental merge.
*/
if( !isFts4 && !isCreate ){
int rc2 = SQLITE_OK;
fts3DbExec(&rc2, db, "SELECT 1 FROM %Q.'%q_stat' WHERE id=2",
p->zDb, p->zName);
if( rc2==SQLITE_OK ) p->bHasStat = 1;
p->bHasStat = 2;
}
/* Figure out the page-size for the database. This is required in order to
@@ -3320,7 +3317,34 @@ static int fts3SyncMethod(sqlite3_vtab *pVtab){
}
/*
** Implementation of xBegin() method. This is a no-op.
** If it is currently unknown whether or not the FTS table has an %_stat
** table (if p->bHasStat==2), attempt to determine this (set p->bHasStat
** to 0 or 1). Return SQLITE_OK if successful, or an SQLite error code
** if an error occurs.
*/
static int fts3SetHasStat(Fts3Table *p){
int rc = SQLITE_OK;
if( p->bHasStat==2 ){
const char *zFmt ="SELECT 1 FROM %Q.sqlite_master WHERE tbl_name='%q_stat'";
char *zSql = sqlite3_mprintf(zFmt, p->zDb, p->zName);
if( zSql ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
int bHasStat = (sqlite3_step(pStmt)==SQLITE_ROW);
rc = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ) p->bHasStat = bHasStat;
}
sqlite3_free(zSql);
}else{
rc = SQLITE_NOMEM;
}
}
return rc;
}
/*
** Implementation of xBegin() method.
*/
static int fts3BeginMethod(sqlite3_vtab *pVtab){
Fts3Table *p = (Fts3Table*)pVtab;
@@ -3331,7 +3355,7 @@ static int fts3BeginMethod(sqlite3_vtab *pVtab){
TESTONLY( p->inTransaction = 1 );
TESTONLY( p->mxSavepoint = -1; );
p->nLeafAdd = 0;
return SQLITE_OK;
return fts3SetHasStat(p);
}
/*
@@ -3580,6 +3604,10 @@ static int fts3RenameMethod(
sqlite3 *db = p->db; /* Database connection */
int rc; /* Return Code */
/* At this point it must be known if the %_stat table exists or not.
** So bHasStat may not be 2. */
rc = fts3SetHasStat(p);
/* As it happens, the pending terms table is always empty here. This is
** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
** always opens a savepoint transaction. And the xSavepoint() method
@@ -3587,7 +3615,9 @@ static int fts3RenameMethod(
** PendingTermsFlush() in in case that changes.
*/
assert( p->nPendingData==0 );
rc = sqlite3Fts3PendingTermsFlush(p);
if( rc==SQLITE_OK ){
rc = sqlite3Fts3PendingTermsFlush(p);
}
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
+1 -1
View File
@@ -223,7 +223,7 @@ struct Fts3Table {
int nNodeSize; /* Soft limit for node size */
u8 bFts4; /* True for FTS4, false for FTS3 */
u8 bHasStat; /* True if %_stat table exists */
u8 bHasStat; /* True if %_stat table exists (2==unknown) */
u8 bHasDocsize; /* True if %_docsize table exists */
u8 bDescIdx; /* True if doclists are in reverse order */
u8 bIgnoreSavepoint; /* True to ignore xSavepoint invocations */
+4
View File
@@ -5271,6 +5271,10 @@ int sqlite3Fts3UpdateMethod(
int nChng = 0; /* Net change in number of documents */
int bInsertDone = 0;
/* At this point it must be known if the %_stat table exists or not.
** So bHasStat may not be 2. */
assert( p->bHasStat==0 || p->bHasStat==1 );
assert( p->pSegments==0 );
assert(
nArg==1 /* DELETE operations */
+23 -15
View File
@@ -2947,26 +2947,32 @@ static int rtreeRename(sqlite3_vtab *pVtab, const char *zNewName){
** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
*/
static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
const char *zSql = "SELECT stat FROM sqlite_stat1 WHERE tbl= ? || '_rowid'";
const char *zFmt = "SELECT stat FROM %Q.sqlite_stat1 WHERE tbl = '%q_rowid'";
char *zSql;
sqlite3_stmt *p;
int rc;
i64 nRow = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_text(p, 1, pRtree->zName, -1, SQLITE_STATIC);
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
rc = sqlite3_finalize(p);
}else if( rc!=SQLITE_NOMEM ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
if( nRow==0 ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
}else{
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
zSql = sqlite3_mprintf(zFmt, pRtree->zDb, pRtree->zName);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v2(db, zSql, -1, &p, 0);
if( rc==SQLITE_OK ){
if( sqlite3_step(p)==SQLITE_ROW ) nRow = sqlite3_column_int64(p, 0);
rc = sqlite3_finalize(p);
}else if( rc!=SQLITE_NOMEM ){
rc = SQLITE_OK;
}
if( rc==SQLITE_OK ){
if( nRow==0 ){
pRtree->nRowEst = RTREE_DEFAULT_ROWEST;
}else{
pRtree->nRowEst = MAX(nRow, RTREE_MIN_ROWEST);
}
}
sqlite3_free(zSql);
}
return rc;
@@ -3235,6 +3241,8 @@ static int rtreeInit(
if( rc==SQLITE_OK ){
*ppVtab = (sqlite3_vtab *)pRtree;
}else{
assert( *ppVtab==0 );
assert( pRtree->nBusy==1 );
rtreeRelease(pRtree);
}
return rc;
+112
View File
@@ -158,5 +158,117 @@ do_execsql_test 4.3 {
SELECT b, a FROM t2 LEFT JOIN t1 ON (+a = +b);
} {1 1 3 {}}
#--------------------------------------------------------------------
# Test that the sqlite_stat1 data is used correctly.
#
reset_db
do_execsql_test 5.1 {
CREATE TABLE t1(x PRIMARY KEY, y);
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
INSERT INTO t1(x) VALUES(1);
INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2
INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4
INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8
INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16
INSERT INTO t1(x) SELECT x+16 FROM t1; -- 32
INSERT INTO t1(x) SELECT x+32 FROM t1; -- 64
INSERT INTO t1(x) SELECT x+64 FROM t1; -- 128
INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256
INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512
INSERT INTO t1(x) SELECT x+512 FROM t1; --1024
INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5;
}
# First test a query with no ANALYZE data at all. The outer loop is
# real table "t1".
#
do_eqp_test 5.2 {
SELECT * FROM t1, rt WHERE x==id;
} {
0 0 0 {SCAN TABLE t1}
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
}
# Now create enough ANALYZE data to tell SQLite that virtual table "rt"
# contains very few rows. This causes it to move "rt" to the outer loop.
#
do_execsql_test 5.3 {
ANALYZE;
DELETE FROM sqlite_stat1 WHERE tbl='t1';
}
db close
sqlite3 db test.db
do_eqp_test 5.4 {
SELECT * FROM t1, rt WHERE x==id;
} {
0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:}
0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)}
}
# Delete the ANALYZE data. "t1" should be the outer loop again.
#
do_execsql_test 5.5 { DROP TABLE sqlite_stat1; }
db close
sqlite3 db test.db
do_eqp_test 5.6 {
SELECT * FROM t1, rt WHERE x==id;
} {
0 0 0 {SCAN TABLE t1}
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
}
# This time create and attach a database that contains ANALYZE data for
# tables of the same names as those used internally by virtual table
# "rt". Check that the rtree module is not fooled into using this data.
# Table "t1" should remain the outer loop.
#
do_test 5.7 {
db backup test.db2
sqlite3 db2 test.db2
db2 eval {
ANALYZE;
DELETE FROM sqlite_stat1 WHERE tbl='t1';
}
db2 close
db close
sqlite3 db test.db
execsql { ATTACH 'test.db2' AS aux; }
} {}
do_eqp_test 5.8 {
SELECT * FROM t1, rt WHERE x==id;
} {
0 0 0 {SCAN TABLE t1}
0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:}
}
#--------------------------------------------------------------------
# Test that having a second connection drop the sqlite_stat1 table
# before it is required by rtreeConnect() does not cause problems.
#
ifcapable rtree {
reset_db
do_execsql_test 6.1 {
CREATE TABLE t1(x);
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
INSERT INTO t1 VALUES(1);
INSERT INTO rt VALUES(1,2,3);
ANALYZE;
}
db close
sqlite3 db test.db
do_execsql_test 6.2 { SELECT * FROM t1 } {1}
do_test 6.3 {
sqlite3 db2 test.db
db2 eval { DROP TABLE sqlite_stat1 }
db2 close
execsql { SELECT * FROM rt }
} {1 2.0 3.0}
db close
}
finish_test
+57
View File
@@ -0,0 +1,57 @@
# 2014 March 11
#
# 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.
#
#***********************************************************************
#
# Miscellaneous tests for errors in the rtree constructor.
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] rtree_util.tcl]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
ifcapable !rtree {
finish_test
return
}
set testprefix rtreeD
#-------------------------------------------------------------------------
# Test that if an SQLITE_BUSY is encountered within the vtable
# constructor, a relevant error message is returned.
#
do_multiclient_test tn {
do_test 1.$tn.1 {
sql1 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1,2);
CREATE VIRTUAL TABLE rt USING rtree(id, minx, maxx, miny, maxy);
INSERT INTO rt VALUES(1,2,3,4,5);
}
} {}
do_test 1.$tn.2 {
sql2 { SELECT * FROM t1; }
} {1 2}
do_test 1.$tn.3 {
sql1 { BEGIN EXCLUSIVE; INSERT INTO t1 VALUES(3, 4); }
} {}
do_test 1.$tn.4 {
list [catch { sql2 { SELECT * FROM rt } } msg] $msg
} {1 {database is locked}}
}
finish_test
+2 -1
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 \
+80 -72
View File
@@ -1,12 +1,12 @@
C Version\s3.8.4
D 2014-03-10T12:20:37.813
C Experimental\smulti-threaded\ssorting\schanges\sto\sbegin\smerging\sPMAs\sbefore\sSorterRewind()\sis\scalled.
D 2014-04-07T18:44:00.443
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 153eb9b9725bc7b8e4dbe963219298e0c4a644b0
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
F VERSION 0dc30ad5cf90736d5fd9e540c9f05c542658abe7
F VERSION 9f823c026c6a32fc5f84d212a8aae0a221dba45c
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure e12e1a4f031354f9af735bcb377941a72dc2cca5 x
F configure 5de98fac90452f876511fee8a35565a55dfb191f x
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
@@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 3fe91e36a0304ad4b35020f0e22ff37e95873166
F ext/fts3/fts3.c 41b1920b9a8657963f09cb93b208c2671c5568db
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1
F ext/fts3/fts3Int.h bdeb9015405e8facffb8fc7e09174521a2a780f4
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
F ext/fts3/fts3_expr.c 5165c365cb5a035f5be8bb296f7aa3211d43e4ac
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
@@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9
F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d
F ext/fts3/fts3_write.c cdebe72171a217b1465032dec103f8d17f7dad4d
F ext/fts3/fts3_write.c 74c00329006c3ed6325ba4e5ab7c9b5fc99c8934
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
@@ -120,7 +120,7 @@ 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 a4e18b2c150adad20aecbeb3408cd235a0a57441
F ext/rtree/rtree.c 2d9f95da404d850474e628c720c5ce15d29b47de
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
@@ -133,7 +133,8 @@ 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 03975565f40a0bee165f613143e4dec716dd5a59
F ext/rtree/rtreeC.test 16d7aa86ecb6a876d2a38cf590a1471a41b3a46d
F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
@@ -142,7 +143,7 @@ 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 4b30dd2a6cb441db688972496b45a6c3abef8b20
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -163,20 +164,20 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 4d28fb15543f0e071b1780b2af8cd2ee489de32d
F src/btree.h 9e0f97c01b972f779eb7655cfb4f8727fd6dc26f
F src/btree.c 0d1be67448c45eccc40114556186397eb9da7f7d
F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba
F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0
F src/build.c e120a3693ac78ab3e74048205f07a3a522d9b982
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c cdd57149543bb28304d8f717c243f2a86b1fc280
F src/expr.c 014b8087a15c4c314bdd798cb1cb0b32693f8b40
F src/expr.c da2b3cb41081af6b56e95e7c9e95949564ce2e21
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 5269ef07b100763134f71b889327c333bd0989cf
F src/func.c 2945bb2c4cdc0ac43733046285a4434310be1811
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
F src/global.c deadd872189b92aca4ee2566332a86315839f811
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@@ -185,13 +186,13 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
F src/main.c e054917b1beb3081b0f23e8bdd3d6c0e12933dd3
F src/main.c fcceb01d74a79c2d7984f33545b35b06da3bb1e8
F src/malloc.c 0203ebce9152c6a0e5de520140b8ba65187350be
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c aeb019f271ea53de83d651ec526877e6ba863450
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
@@ -202,31 +203,31 @@ 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 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5
F src/os_win.c e71678ac927d0a0fb11d993db20a9748eabf808e
F src/pager.c 97a8908bf4e6e7c3adea09d3597cfa48ae33ab4e
F src/os_unix.c ae4b5240af4619d711301d7992396e182585269f
F src/os_win.c 8245fe9184300e641d02e29a8ca95cefe0cb0fd0
F src/pager.c ab62a24218d87dda1be641f6c5ad291bff78fd94
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 2613ca5d609c2f3d71dd297351f010bcec16e1e0
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
F src/pragma.c a46ee83671f5c95f53d2ceeb5e1a818d7b1df99a
F src/pragma.c 10f169b9650f0930a7a6df67e1387a4c2c449f38
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
F src/printf.c e5a0005f8b3de21f85da6a709d2fbee76775bf4b
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 273d5f47c4e2c05b2d3d2bffeda939551ab59e66
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 0adf172d33cc610ff5ffe26edfd2ba67c3551655
F src/shell.c bab4de12b441369491812ecc93212ff4deda68fa
F src/sqlite.h.in a2ef671f92747a5a1c8a47bad5c585a8dd9eca80
F src/select.c 20055cf917222e660c4222fea306bd13a0623caa
F src/shell.c b44c3f17f0bf41b3431e9cc171706251156ae85f
F src/sqlite.h.in 81221c50addbf698c3247154d92efd1095bfd885
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h fa7161b3de18a9c355d4148233f3563c92311fcc
F src/sqliteInt.h 533154bf9d8401ff3e6f8030f4373774c0a6ad41
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 0cd73ae82fdf7add76ca603e3575380ae7539ae2
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -239,7 +240,7 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
F src/test_config.c 0336e0bdbe541b4af89d7e3dd0656e8e6b51e585
F src/test_config.c ebd0a42983b696f2b121515d577753cf2afdc9b0
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
@@ -250,7 +251,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
@@ -265,33 +266,34 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e
F src/test_stat.c 9898687a6c2beca733b0dd6fe19163d987826d31
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091
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_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c b8e7232f2b9c9d148d6886117160de394d172f85
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
F src/trigger.c a80036fcbd992729adc7cd34a875d59a71fa10cc
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 5f0fffa9bf49a90c05dc3d46d8217603fd0ee00e
F src/vdbe.h d189f92468a17a6f04daeec9df3b767f50557b21
F src/vdbeInt.h e54fc4f289fce48e81b3371128446033d097733b
F src/vdbe.c 9f3d1b35b5fe8c7f3a4f734bd524d0df844a2576
F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
F src/vdbeInt.h ba1069627d0ab75e9ddb8f9c10958b86cdbd333d
F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
F src/vdbeaux.c e45e3f9daf38c5be3fd39e9aacc1c9066af57a06
F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50
F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
F src/vdbesort.c 46801acb342e5e4c07ba1777fe58880c143abb59
F src/vdbesort.c 07c29a5a61e041eeb1c366eefef9e99dfe5e2174
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 95d30485879122acc5284d4523e01399b23b6148
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
F src/where.c 70eb10da08cebbd6a576ced18edb7c8f79d41597
F src/whereInt.h 2564055b440e44ebec8b47f237bbccae6719b7af
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -402,9 +404,9 @@ F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test 58ec333a01997fe655e34e5bea52b7a2a6b9704d
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
F test/corruptI.test 88886ec9cd1bdba835263566bbf60ee009c6ea09
F test/corruptI.test b3e4203d420490fc3d3062711597bc1dea06a789
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
@@ -430,7 +432,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
@@ -522,7 +524,7 @@ F test/fts3ak.test bd14deafe9d1586e8e9bf032411026ac4f8c925d
F test/fts3al.test 07d64326e79bbdbab20ee87fc3328fbf01641c9f
F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda
F test/fts3ao.test 3e4e3d5e75c076520341d0bdf4eb17c00e8cbde2
F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451
F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9
F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221
@@ -534,7 +536,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de
F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb
F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F test/fts3d.test c8a193513a269ec4c205ca09645e26e0bc71b860
F test/fts3d.test 597b0b76e41f0d672e2731c4d7b631d628efd13f
F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963
F test/fts3defer2.test a3b6cbeabaf28c9398652a4d101ea224d9358479
F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd
@@ -592,7 +594,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
@@ -647,7 +649,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
F test/like.test e191e536d0fcd722a6b965e7cd1ee0bfd12a5991
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
F test/limit.test 3d7df19c35ac672a11f7de406cd3205d592babbb
F test/loadext.test 648cb95f324d1775c54a55c12271b2d1156b633b
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
@@ -661,7 +663,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 26ae08a09cc15a98d147ee63925e3a66048e71c9
F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
@@ -669,7 +671,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
@@ -721,7 +723,8 @@ F test/orderby1.test 9b524aff9147288da43a6d7ddfdcff47fa2303c6
F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c
F test/orderby5.test 2490183fef54417209d1df253633a605d46bd350
F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
@@ -735,7 +738,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 a214a42b4767bbbc7cd0fd965ea6198044ab414d
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@@ -810,11 +813,13 @@ F test/shell5.test bb755ea9144b8078a752fc56223582627070b5f1
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
F test/skipscan1.test 8c777ffd9dad6ee6d2568160cb2158f0b5cd9dd2
F test/skipscan1.test bed8cbe9d554c8c27afb6c88500f704c86a9196f
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/sort.test 79dc647c4e9b123a64e57b7080b7f9a2df43f87a
F test/sort2.test 21cd865e31adecdc8fc81c8d95431e629676a8d8
F test/sort3.test c3f88d233452a129de519de311d109a0ad0da0af
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
@@ -823,7 +828,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 1603da7b4897716f9df15bd71b0310f56ec3181e
F test/speedtest1.c 90446861e566a9965a8d005381a3c964ff333646
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
@@ -834,7 +839,7 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
@@ -843,7 +848,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
@@ -890,6 +895,7 @@ F test/tkt-94c04eaadb.test f738c57c7f68ab8be1c054415af7774617cb6223
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
F test/tkt-9f2eb3abac.test 85bc63e749f050e6a61c8f9207f1eee65c9d3395
F test/tkt-a7b7803e.test 159ef554234fa1f9fb318c751b284bd1cf858da4
F test/tkt-a8a0d2996a.test eb597379dbcefa24765763d7f682c00cb5924fa9
F test/tkt-b1d3a2e531.test 8f7576e41ca179289ee1a8fee28386fd8e4b0550
F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
F test/tkt-b72787b1.test a95e8cdad0b98af1853ac7f0afd4ab27b77bf5f3
@@ -1046,13 +1052,14 @@ F test/vtabE.test 7c4693638d7797ce2eda17af74292b97e705cc61
F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 6acafaae7126c9f49be72c2f57eb8bef3024f1cb
F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285
F test/vtab_shared.test ea8778d5b0df200adef2ca7c00c3c37d4375f772
F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216
F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750
@@ -1088,14 +1095,15 @@ F test/whereC.test d6f4ecd4fa2d9429681a5b22a25d2bda8e86ab8a
F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f
F test/whereG.test 2533b72ed4a31fd1687230a499b557b911525344
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
F test/with2.test ee227a663586aa09771cafd4fa269c5217eaf775
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
F test/without_rowid1.test e00a0a9dc9f0be651f011d61e8a32b7add5afb30
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
@@ -1117,14 +1125,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 7ad625cac3d54012b27d468b7af6612f78b9ba75
F tool/logest.c 388c318c7ac8b52b7c08ca1e2de0f4ca9a8f7e81
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
@@ -1155,10 +1163,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P ba39df9d4f7ffc6475ae0dc794f7d3f58c486de8
R f73df97bd275791734e233575a443767
T +bgcolor * #d0c0ff
T +sym-release *
T +sym-version-3.8.4 *
U drh
Z 82f901d4413784b1ea9af3cba9303801
P e54dded2012f0ab486ee138e9bd57c528af33980
R 020c9d4d2bbea35c99aea5cfddab0eac
T *branch * threads-experimental
T *sym-threads-experimental *
T -sym-threads *
U dan
Z 16c0542d21b377d284993b464ea194ff
+1 -1
View File
@@ -1 +1 @@
530a1ee7dc2435f80960ce4710a3c2d2bfaaccc5
cbfc0f6d49b6607bb4eb45bfe4c258e39ac27403
+36 -4
View File
@@ -746,20 +746,32 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
** at is deleted out from under them.
**
** This routine returns an error code if something goes wrong. The
** integer *pHasMoved is set to one if the cursor has moved and 0 if not.
** integer *pHasMoved is set as follows:
**
** 0: The cursor is unchanged
** 1: The cursor is still pointing at the same row, but the pointers
** returned by sqlite3BtreeKeyFetch() or sqlite3BtreeDataFetch()
** might now be invalid because of a balance() or other change to the
** b-tree.
** 2: The cursor is no longer pointing to the row. The row might have
** been deleted out from under the cursor.
*/
int sqlite3BtreeCursorHasMoved(BtCursor *pCur, int *pHasMoved){
int rc;
if( pCur->eState==CURSOR_VALID ){
*pHasMoved = 0;
return SQLITE_OK;
}
rc = restoreCursorPosition(pCur);
if( rc ){
*pHasMoved = 1;
*pHasMoved = 2;
return rc;
}
if( pCur->eState!=CURSOR_VALID || NEVER(pCur->skipNext!=0) ){
*pHasMoved = 1;
*pHasMoved = 2;
}else{
*pHasMoved = 0;
*pHasMoved = 1;
}
return SQLITE_OK;
}
@@ -2161,6 +2173,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
return SQLITE_OK;
}
#if SQLITE_MAX_MMAP_SIZE>0
/*
** Change the limit on the amount of the database file that may be
** memory mapped.
@@ -2173,6 +2186,7 @@ int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 szMmap){
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
#endif /* SQLITE_MAX_MMAP_SIZE>0 */
/*
** Change the way data is synced to disk in order to increase or decrease
@@ -4186,10 +4200,13 @@ static const void *fetchPayload(
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
assert( pCur->info.nSize>0 );
#if 0
if( pCur->info.nSize==0 ){
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
&pCur->info);
}
#endif
*pAmt = pCur->info.nLocal;
return (void*)(pCur->info.pCell + pCur->info.nHeader);
}
@@ -4571,6 +4588,7 @@ int sqlite3BtreeMovetoUnpacked(
if( pIdxKey ){
xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
pIdxKey->errCode = 0;
assert( pIdxKey->default_rc==1
|| pIdxKey->default_rc==0
|| pIdxKey->default_rc==-1
@@ -4694,6 +4712,10 @@ int sqlite3BtreeMovetoUnpacked(
c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
sqlite3_free(pCellKey);
}
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 ){
@@ -4703,6 +4725,7 @@ int sqlite3BtreeMovetoUnpacked(
*pRes = 0;
rc = SQLITE_OK;
pCur->aiIdx[pCur->iPage] = (u16)idx;
if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
goto moveto_finish;
}
if( lwr>upr ) break;
@@ -7423,6 +7446,15 @@ int sqlite3BtreeClearTable(Btree *p, int iTable, int *pnChange){
return rc;
}
/*
** Delete all information from the single table that pCur is open on.
**
** This routine only work for pCur on an ephemeral table.
*/
int sqlite3BtreeClearTableOfCursor(BtCursor *pCur){
return sqlite3BtreeClearTable(pCur->pBtree, pCur->pgnoRoot, 0);
}
/*
** Erase all information in a table and add the root of the table to
** the freelist. Except, the root of the principle table (the one on
+4 -1
View File
@@ -63,7 +63,9 @@ int sqlite3BtreeOpen(
int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#if SQLITE_MAX_MMAP_SIZE>0
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
#endif
int sqlite3BtreeSetPagerFlags(Btree*,unsigned);
int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);
@@ -113,6 +115,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
int sqlite3BtreeDropTable(Btree*, int, int*);
int sqlite3BtreeClearTable(Btree*, int, int*);
int sqlite3BtreeClearTableOfCursor(BtCursor*);
void sqlite3BtreeTripAllCursors(Btree*, int);
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
+2 -2
View File
@@ -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
@@ -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;
+9 -6
View File
@@ -33,6 +33,7 @@
char sqlite3ExprAffinity(Expr *pExpr){
int op;
pExpr = sqlite3ExprSkipCollate(pExpr);
if( pExpr->flags & EP_Generic ) return SQLITE_AFF_NONE;
op = pExpr->op;
if( op==TK_SELECT ){
assert( pExpr->flags&EP_xIsSelect );
@@ -65,7 +66,11 @@ char sqlite3ExprAffinity(Expr *pExpr){
** If a memory allocation error occurs, that fact is recorded in pParse->db
** and the pExpr parameter is returned unchanged.
*/
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr *pExpr, Token *pCollName){
Expr *sqlite3ExprAddCollateToken(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* Add the "COLLATE" clause to this expression */
const Token *pCollName /* Name of collating sequence */
){
if( pCollName->n>0 ){
Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLLATE, pCollName, 1);
if( pNew ){
@@ -118,6 +123,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){
Expr *p = pExpr;
while( p ){
int op = p->op;
if( p->flags & EP_Generic ) break;
if( op==TK_CAST || op==TK_UPLUS ){
p = p->pLeft;
continue;
@@ -949,7 +955,6 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
if( p==0 ) return 0;
pNew = sqlite3DbMallocRaw(db, sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->iECursor = 0;
pNew->nExpr = i = p->nExpr;
if( (flags & EXPRDUP_REDUCE)==0 ) for(i=1; i<p->nExpr; i+=i){}
pNew->a = pItem = sqlite3DbMallocRaw(db, i*sizeof(p->a[0]) );
@@ -1062,7 +1067,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
pNew->nSelectRow = p->nSelectRow;
pNew->pWith = withDup(db, p->pWith);
return pNew;
@@ -1630,7 +1634,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
*prNotFound = rMayHaveNull = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}else{
testcase( pParse->nQueryLoop>0 );
pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID;
@@ -2335,7 +2338,7 @@ void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){
int i;
struct yColCache *p;
assert( iFrom>=iTo+nReg || iFrom+nReg<=iTo );
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg-1);
sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);
for(i=0, p=pParse->aColCache; i<SQLITE_N_COLCACHE; i++, p++){
int x = p->iReg;
if( x>=iFrom && x<iFrom+nReg ){
@@ -2736,7 +2739,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
sqlite3ExprCodeExprList(pParse, pFarg, r1,
sqlite3ExprCodeExprList(pParse, pFarg, r1,
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
}else{
+1
View File
@@ -167,6 +167,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
0, /* nPage */
0, /* mxParserStack */
0, /* sharedCacheEnabled */
0, /* nWorker */
/* All the rest should always be initialized to zero */
0, /* isInit */
0, /* inProgress */
+16
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;
@@ -800,6 +807,7 @@ static void disconnectAllVtab(sqlite3 *db){
}
}
}
sqlite3VtabUnlockList(db);
sqlite3BtreeLeaveAll(db);
#else
UNUSED_PARAMETER(db);
@@ -2496,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
@@ -3322,6 +3331,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
@@ -248,7 +248,7 @@ static void *memsys5MallocUnsafe(int nByte){
** block. If not, then split a block of the next larger power of
** two in order to create a new free block of size iLogsize.
*/
for(iBin=iLogsize; mem5.aiFreelist[iBin]<0 && iBin<=LOGMAX; iBin++){}
for(iBin=iLogsize; iBin<=LOGMAX && mem5.aiFreelist[iBin]<0; iBin++){}
if( iBin>LOGMAX ){
testcase( sqlite3GlobalConfig.xLog!=0 );
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
+59 -23
View File
@@ -323,6 +323,7 @@ static int posixFchown(int fd, uid_t uid, gid_t gid){
/* Forward reference */
static int openDirectory(const char*, int*);
static int unixGetpagesize(void);
/*
** Many system calls are accessed through pointer-to-functions so that
@@ -446,6 +447,9 @@ static struct unix_syscall {
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
#endif
{ "getpagesize", (sqlite3_syscall_ptr)unixGetpagesize, 0 },
#define osGetpagesize ((int(*)(void))aSyscall[24].pCurrent)
}; /* End of the overrideable system calls */
/*
@@ -4105,6 +4109,36 @@ static int unixShmSystemLock(
return rc;
}
/*
** Return the system page size.
**
** This function should not be called directly by other code in this file.
** Instead, it should be called via macro osGetpagesize().
*/
static int unixGetpagesize(void){
#if defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
#endif
}
/*
** Return the minimum number of 32KB shm regions that should be mapped at
** a time, assuming that each mapping must be an integer multiple of the
** current system page-size.
**
** Usually, this is 1. The exception seems to be systems that are configured
** to use 64KB pages - in this case each mapping must cover at least two
** shm regions.
*/
static int unixShmRegionPerMap(void){
int shmsz = 32*1024; /* SHM region size */
int pgsz = osGetpagesize(); /* System page size */
assert( ((pgsz-1)&pgsz)==0 ); /* Page size must be a power of 2 */
if( pgsz<shmsz ) return 1;
return pgsz/shmsz;
}
/*
** Purge the unixShmNodeList list of all entries with unixShmNode.nRef==0.
@@ -4116,10 +4150,11 @@ static void unixShmPurge(unixFile *pFd){
unixShmNode *p = pFd->pInode->pShmNode;
assert( unixMutexHeld() );
if( p && p->nRef==0 ){
int nShmPerMap = unixShmRegionPerMap();
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->h>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
}else{
@@ -4326,6 +4361,8 @@ static int unixShmMap(
unixShm *p;
unixShmNode *pShmNode;
int rc = SQLITE_OK;
int nShmPerMap = unixShmRegionPerMap();
int nReqRegion;
/* If the shared-memory file has not yet been opened, open it now. */
if( pDbFd->pShm==0 ){
@@ -4341,9 +4378,12 @@ static int unixShmMap(
assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 );
assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 );
if( pShmNode->nRegion<=iRegion ){
/* Minimum number of regions required to be mapped. */
nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap;
if( pShmNode->nRegion<nReqRegion ){
char **apNew; /* New apRegion[] array */
int nByte = (iRegion+1)*szRegion; /* Minimum required file size */
int nByte = nReqRegion*szRegion; /* Minimum required file size */
struct stat sStat; /* Used by fstat() */
pShmNode->szRegion = szRegion;
@@ -4392,17 +4432,19 @@ static int unixShmMap(
/* Map the requested memory region into this processes address space. */
apNew = (char **)sqlite3_realloc(
pShmNode->apRegion, (iRegion+1)*sizeof(char *)
pShmNode->apRegion, nReqRegion*sizeof(char *)
);
if( !apNew ){
rc = SQLITE_IOERR_NOMEM;
goto shmpage_out;
}
pShmNode->apRegion = apNew;
while(pShmNode->nRegion<=iRegion){
while( pShmNode->nRegion<nReqRegion ){
int nMap = szRegion*nShmPerMap;
int i;
void *pMem;
if( pShmNode->h>=0 ){
pMem = osMmap(0, szRegion,
pMem = osMmap(0, nMap,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
);
@@ -4418,8 +4460,11 @@ static int unixShmMap(
}
memset(pMem, 0, szRegion);
}
pShmNode->apRegion[pShmNode->nRegion] = pMem;
pShmNode->nRegion++;
for(i=0; i<nShmPerMap; i++){
pShmNode->apRegion[pShmNode->nRegion+i] = &((char*)pMem)[szRegion*i];
}
pShmNode->nRegion += nShmPerMap;
}
}
@@ -4633,19 +4678,6 @@ static void unixUnmapfile(unixFile *pFd){
}
}
/*
** Return the system page size.
*/
static int unixGetPagesize(void){
#if HAVE_MREMAP
return 512;
#elif defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
#endif
}
/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
@@ -4682,8 +4714,12 @@ static void unixRemapfile(
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
const int szSyspage = unixGetPagesize();
#if HAVE_MREMAP
i64 nReuse = pFd->mmapSize;
#else
const int szSyspage = osGetpagesize();
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
#endif
u8 *pReq = &pOrig[nReuse];
/* Unmap any pages of the existing mapping that cannot be reused. */
@@ -7429,7 +7465,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==24 );
assert( ArraySize(aSyscall)==25 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
+7
View File
@@ -1279,6 +1279,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.
+1 -2
View File
@@ -1624,12 +1624,11 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
if( !zMaster
|| pPager->journalMode==PAGER_JOURNALMODE_MEMORY
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| !isOpen(pPager->jfd)
){
return SQLITE_OK;
}
pPager->setMaster = 1;
assert( isOpen(pPager->jfd) );
assert( pPager->journalHdr <= pPager->journalOff );
/* Calculate the length in bytes and the checksum of zMaster */
+27
View File
@@ -1020,6 +1020,33 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
*/
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
sqlite3ExprDelete(pParse->db, X.pExpr);
}else if( Y->nExpr==1 ){
/* Expressions of the form:
**
** expr1 IN (?1)
** expr1 NOT IN (?2)
**
** with exactly one value on the RHS can be simplified to something
** like this:
**
** expr1 == ?1
** expr1 <> ?2
**
** But, the RHS of the == or <> is marked with the EP_Generic flag
** so that it may not contribute to the computation of comparison
** affinity or the collating sequence to use for comparison. Otherwise,
** the semantics would be subtly different from IN or NOT IN.
*/
Expr *pRHS = Y->a[0].pExpr;
Y->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, Y);
/* pRHS cannot be NULL because a malloc error would have been detected
** before now and control would have never reached this point */
if( ALWAYS(pRHS) ){
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
}else{
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
+4 -4
View File
@@ -824,7 +824,7 @@ void sqlite3Pragma(
** size of historical compatibility.
*/
case PragTyp_DEFAULT_CACHE_SIZE: {
static const int iLn = __LINE__+2;
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList getCacheSize[] = {
{ OP_Transaction, 0, 0, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_DEFAULT_CACHE_SIZE}, /* 1 */
@@ -1087,7 +1087,7 @@ void sqlite3Pragma(
** file. Before writing to meta[6], check that meta[3] indicates
** that this really is an auto-vacuum capable database.
*/
static const int iLn = __LINE__+2;
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList setMeta6[] = {
{ OP_Transaction, 0, 1, 0}, /* 0 */
{ OP_ReadCookie, 0, 1, BTREE_LARGEST_ROOT_PAGE},
@@ -1790,7 +1790,7 @@ void sqlite3Pragma(
** messages have been generated, output OK. Otherwise output the
** error message
*/
static const int iLn = __LINE__+2;
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = {
{ OP_AddImm, 1, 0, 0}, /* 0 */
{ OP_IfNeg, 1, 0, 0}, /* 1 */
@@ -1875,7 +1875,7 @@ void sqlite3Pragma(
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName),
P4_DYNAMIC);
sqlite3VdbeAddOp2(v, OP_Move, 2, 4);
sqlite3VdbeAddOp3(v, OP_Move, 2, 4, 1);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2);
sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1);
sqlite3VdbeJumpHere(v, addr);
+84 -77
View File
@@ -134,20 +134,6 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
/*
** Append N space characters to the given string buffer.
*/
void sqlite3AppendSpace(StrAccum *pAccum, int N){
static const char zSpaces[] = " ";
while( N>=(int)sizeof(zSpaces)-1 ){
sqlite3StrAccumAppend(pAccum, zSpaces, sizeof(zSpaces)-1);
N -= sizeof(zSpaces)-1;
}
if( N>0 ){
sqlite3StrAccumAppend(pAccum, zSpaces, N);
}
}
/*
** Set the StrAccum object to an error mode.
*/
@@ -237,11 +223,9 @@ void sqlite3VXPrintf(
}
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
int amt;
bufpt = (char *)fmt;
amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
sqlite3StrAccumAppend(pAccum, bufpt, amt);
while( (c=(*++fmt))!='%' && c!=0 ){};
sqlite3StrAccumAppend(pAccum, bufpt, (int)(fmt - bufpt));
if( c==0 ) break;
}
if( (c=(*++fmt))==0 ){
@@ -422,10 +406,8 @@ void sqlite3VXPrintf(
*(--bufpt) = zOrd[x*2];
}
{
register const char *cset; /* Use registers for speed */
register int base;
cset = &aDigits[infop->charset];
base = infop->base;
const char *cset = &aDigits[infop->charset];
u8 base = infop->base;
do{ /* Convert to ascii */
*(--bufpt) = cset[longvalue%base];
longvalue = longvalue/base;
@@ -729,29 +711,89 @@ void sqlite3VXPrintf(
** "length" characters long. The field width is "width". Do
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
sqlite3AppendSpace(pAccum, nspace);
}
}
if( length>0 ){
sqlite3StrAccumAppend(pAccum, bufpt, length);
}
if( flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
sqlite3AppendSpace(pAccum, nspace);
}
}
width -= length;
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
sqlite3StrAccumAppend(pAccum, bufpt, length);
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( zExtra ) sqlite3_free(zExtra);
}/* End for loop over the format string */
} /* End of function */
/*
** Append N bytes of text from z to the StrAccum object.
** Enlarge the memory allocation on a StrAccum object so that it is
** able to accept at least N more bytes of text.
**
** Return the number of bytes of text that StrAccum is able to accept
** after the attempted enlargement. The value returned might be zero.
*/
static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
char *zNew;
assert( p->nChar+N >= p->nAlloc ); /* Only called if really needed */
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
return 0;
}
if( !p->useMalloc ){
N = p->nAlloc - p->nChar - 1;
setStrAccumError(p, STRACCUM_TOOBIG);
return N;
}else{
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
return 0;
}else{
p->nAlloc = (int)szNew;
}
if( p->useMalloc==1 ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
zNew = sqlite3_realloc(zOld, p->nAlloc);
}
if( zNew ){
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
return 0;
}
}
return N;
}
/*
** Append N space characters to the given string buffer.
*/
void sqlite3AppendSpace(StrAccum *p, int N){
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
}
/*
** The StrAccum "p" is not large enough to accept N new bytes of z[].
** So enlarge if first, then do the append.
**
** This is a helper routine to sqlite3StrAccumAppend() that does special-case
** work (enlarging the buffer) using tail recursion, so that the
** sqlite3StrAccumAppend() routine can use fast calling semantics.
*/
static void enlargeAndAppend(StrAccum *p, const char *z, int N){
N = sqlite3StrAccumEnlarge(p, N);
if( N>0 ){
memcpy(&p->zText[p->nChar], z, N);
p->nChar += N;
}
}
/*
** Append N bytes of text from z to the StrAccum object. Increase the
** size of the memory allocation for StrAccum if necessary.
*/
void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( z!=0 );
@@ -759,43 +801,8 @@ void sqlite3StrAccumAppend(StrAccum *p, const char *z, int N){
assert( N>=0 );
assert( p->accError==0 || p->nAlloc==0 );
if( p->nChar+N >= p->nAlloc ){
char *zNew;
if( p->accError ){
testcase(p->accError==STRACCUM_TOOBIG);
testcase(p->accError==STRACCUM_NOMEM);
return;
}
if( !p->useMalloc ){
N = p->nAlloc - p->nChar - 1;
setStrAccumError(p, STRACCUM_TOOBIG);
if( N<=0 ){
return;
}
}else{
char *zOld = (p->zText==p->zBase ? 0 : p->zText);
i64 szNew = p->nChar;
szNew += N + 1;
if( szNew > p->mxAlloc ){
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_TOOBIG);
return;
}else{
p->nAlloc = (int)szNew;
}
if( p->useMalloc==1 ){
zNew = sqlite3DbRealloc(p->db, zOld, p->nAlloc);
}else{
zNew = sqlite3_realloc(zOld, p->nAlloc);
}
if( zNew ){
if( zOld==0 && p->nChar>0 ) memcpy(zNew, p->zText, p->nChar);
p->zText = zNew;
}else{
sqlite3StrAccumReset(p);
setStrAccumError(p, STRACCUM_NOMEM);
return;
}
}
enlargeAndAppend(p,z,N);
return;
}
assert( p->zText );
memcpy(&p->zText[p->nChar], z, N);
+256 -139
View File
@@ -14,6 +14,34 @@
*/
#include "sqliteInt.h"
/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
*/
typedef struct DistinctCtx DistinctCtx;
struct DistinctCtx {
u8 isTnct; /* True if the DISTINCT keyword is present */
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
int tabTnct; /* Ephemeral table used for DISTINCT processing */
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
};
/*
** An instance of the following object is used to record information about
** the ORDER BY (or GROUP BY) clause of query is being coded.
*/
typedef struct SortCtx SortCtx;
struct SortCtx {
ExprList *pOrderBy; /* The ORDER BY (or GROUP BY clause) */
int nOBSat; /* Number of ORDER BY terms satisfied by indices */
int iECursor; /* Cursor number for the sorter */
int regReturn; /* Register holding block-output return address */
int labelBkOut; /* Start label for the block-output subroutine */
int addrSortIndex; /* Address of the OP_SorterOpen or OP_OpenEphemeral */
u8 sortFlags; /* Zero or more SORTFLAG_* bits */
};
#define SORTFLAG_UseSorter 0x01 /* Use SorterOpen instead of OpenEphemeral */
/*
** Delete all the content of a Select structure but do not deallocate
@@ -87,7 +115,6 @@ Select *sqlite3SelectNew(
assert( pOffset==0 || pLimit!=0 );
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->addrOpenEphm[2] = -1;
if( db->mallocFailed ) {
clearSelect(db, pNew);
if( pNew!=&standin ) sqlite3DbFree(db, pNew);
@@ -419,34 +446,98 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
return 0;
}
/* Forward reference */
static KeyInfo *keyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
int nExtra /* Add this many extra columns to the end */
);
/*
** Insert code into "v" that will push the record on the top of the
** stack 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 */
ExprList *pOrderBy, /* The ORDER BY clause */
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 = pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
int op;
sqlite3ExprCacheClear(pParse);
sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1, 1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
if( pSelect->selFlags & SF_UseSorter ){
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 = sqlite3GetTempReg(pParse); /* 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 = sqlite3GetTempRange(pParse, 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 */
int addrJmp; /* Address of the OP_Jump opcode */
VdbeOp *pOp; /* Opcode that opens the sorter */
int nKey; /* Number of sorting key columns, including OP_Sequence */
KeyInfo *pKI; /* Original KeyInfo on the sorter table */
regPrevKey = pParse->nMem+1;
pParse->nMem += pSort->nOBSat;
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;
pKI = pOp->p4.pKeyInfo;
memset(pKI->aSortOrder, 0, pKI->nField); /* Makes OP_Jump below testable */
sqlite3VdbeChangeP4(v, -1, (char*)pKI, P4_KEYINFO);
pOp->p4.pKeyInfo = keyInfoFromExprList(pParse, pSort->pOrderBy, nOBSat, 1);
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(v);
pSort->regReturn = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
sqlite3VdbeJumpHere(v, addrFirst);
sqlite3VdbeAddOp3(v, OP_Move, regBase, regPrevKey, pSort->nOBSat);
sqlite3VdbeJumpHere(v, addrJmp);
}
if( pSort->sortFlags & SORTFLAG_UseSorter ){
op = OP_SorterInsert;
}else{
op = OP_IdxInsert;
}
sqlite3VdbeAddOp2(v, op, pOrderBy->iECursor, regRecord);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nExpr+2);
sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
if( nOBSat==0 ){
sqlite3ReleaseTempReg(pParse, regRecord);
if( nPrefixReg==0 ){
sqlite3ReleaseTempRange(pParse, regBase, nBase);
}
}
if( pSelect->iLimit ){
int addr1, addr2;
int iLimit;
@@ -459,8 +550,8 @@ static void pushOntoSorter(
sqlite3VdbeAddOp2(v, OP_AddImm, iLimit, -1);
addr2 = sqlite3VdbeAddOp0(v, OP_Goto);
sqlite3VdbeJumpHere(v, addr1);
sqlite3VdbeAddOp1(v, OP_Last, pOrderBy->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pOrderBy->iECursor);
sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
sqlite3VdbeJumpHere(v, addr2);
}
}
@@ -473,7 +564,7 @@ static void codeOffset(
int iOffset, /* Register holding the offset counter */
int iContinue /* Jump here to skip the current record */
){
if( iOffset>0 && iContinue!=0 ){
if( iOffset>0 ){
int addr;
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
@@ -534,19 +625,6 @@ static int checkForMultiColumnSelectError(
}
#endif
/*
** An instance of the following object is used to record information about
** how to process the DISTINCT keyword, to simplify passing that information
** into the selectInnerLoop() routine.
*/
typedef struct DistinctCtx DistinctCtx;
struct DistinctCtx {
u8 isTnct; /* True if the DISTINCT keyword is present */
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
int tabTnct; /* Ephemeral table used for DISTINCT processing */
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
};
/*
** This routine generates the code for the inside of the inner loop
** of a SELECT.
@@ -561,7 +639,7 @@ static void selectInnerLoop(
Select *p, /* The complete select statement being coded */
ExprList *pEList, /* List of values being extracted */
int srcTab, /* Pull data from this table */
ExprList *pOrderBy, /* If not NULL, sort results using this key */
SortCtx *pSort, /* If not NULL, info on how to process ORDER BY */
DistinctCtx *pDistinct, /* If not NULL, info on how to process DISTINCT */
SelectDest *pDest, /* How to dispose of the results */
int iContinue, /* Jump here to continue with next row */
@@ -574,11 +652,14 @@ 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 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
if( pOrderBy==0 && !hasDistinct ){
if( pSort && pSort->pOrderBy==0 ) pSort = 0;
if( pSort==0 && !hasDistinct ){
assert( iContinue!=0 );
codeOffset(v, p->iOffset, iContinue);
}
@@ -587,6 +668,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 ){
@@ -668,7 +754,7 @@ static void selectInnerLoop(
break;
}
}
if( pOrderBy==0 ){
if( pSort==0 ){
codeOffset(v, p->iOffset, iContinue);
}
}
@@ -699,16 +785,17 @@ static void selectInnerLoop(
/* Store the result as data using a unique key.
*/
case SRT_DistTable:
case SRT_Fifo:
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_DistTable ){
/* If the destination is DistTable, then cursor (iParm+1) is open
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
** on an ephemeral index. If the current row is already present
** in the index, do not write it to the output. If not, add the
** current row to the index and proceed with writing it to the
@@ -716,11 +803,11 @@ static void selectInnerLoop(
int addr = sqlite3VdbeCurrentAddr(v) + 4;
sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1);
assert( pOrderBy==0 );
assert( pSort==0 );
}
#endif
if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p, r1);
if( pSort ){
pushOntoSorter(pParse, pSort, p, r1+nPrefixReg, 1, nPrefixReg);
}else{
int r2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2);
@@ -728,7 +815,7 @@ static void selectInnerLoop(
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempRange(pParse, r1, nPrefixReg+1);
break;
}
@@ -741,12 +828,12 @@ static void selectInnerLoop(
assert( nResultCol==1 );
pDest->affSdst =
sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst);
if( pOrderBy ){
if( pSort ){
/* At first glance you would think we could optimize out the
** 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, pOrderBy, p, regResult);
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1);
@@ -771,8 +858,8 @@ static void selectInnerLoop(
*/
case SRT_Mem: {
assert( nResultCol==1 );
if( pOrderBy ){
pushOntoSorter(pParse, pOrderBy, p, regResult);
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult, 1, nPrefixReg);
}else{
sqlite3ExprCodeMove(pParse, regResult, iParm, 1);
/* The LIMIT clause will jump out of the loop for us */
@@ -785,11 +872,8 @@ static void selectInnerLoop(
case SRT_Output: { /* Return the results */
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pOrderBy ){
int r1 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1);
pushOntoSorter(pParse, pOrderBy, p, r1);
sqlite3ReleaseTempReg(pParse, r1);
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult, nResultCol, nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
}else{
@@ -865,7 +949,7 @@ static void selectInnerLoop(
** there is a sorter, in which case the sorter has already limited
** the output for us.
*/
if( pOrderBy==0 && p->iLimit ){
if( pSort==0 && p->iLimit ){
sqlite3VdbeAddOp3(v, OP_IfZero, p->iLimit, iBreak, -1); VdbeCoverage(v);
}
}
@@ -936,7 +1020,12 @@ int sqlite3KeyInfoIsWriteable(KeyInfo *p){ return p->nRef==1; }
** function is responsible for seeing that this structure is eventually
** freed.
*/
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
static KeyInfo *keyInfoFromExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* Form the KeyInfo object from this ExprList */
int iStart, /* Begin with this column of pList */
int nExtra /* Add this many extra columns to the end */
){
int nExpr;
KeyInfo *pInfo;
struct ExprList_item *pItem;
@@ -944,15 +1033,15 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList, int nExtra){
int i;
nExpr = pList->nExpr;
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra, 1);
pInfo = sqlite3KeyInfoAlloc(db, nExpr+nExtra-iStart, 1);
if( pInfo ){
assert( sqlite3KeyInfoIsWriteable(pInfo) );
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
for(i=iStart, pItem=pList->a+iStart; i<nExpr; i++, pItem++){
CollSeq *pColl;
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
if( !pColl ) pColl = db->pDfltColl;
pInfo->aColl[i] = pColl;
pInfo->aSortOrder[i] = pItem->sortOrder;
pInfo->aColl[i-iStart] = pColl;
pInfo->aSortOrder[i-iStart] = pItem->sortOrder;
}
}
return pInfo;
@@ -1054,46 +1143,72 @@ static void explainComposite(
static void generateSortTail(
Parse *pParse, /* Parsing context */
Select *p, /* The SELECT statement */
Vdbe *v, /* Generate code into this VDBE */
SortCtx *pSort, /* Information on the ORDER BY clause */
int nColumn, /* Number of columns of data */
SelectDest *pDest /* Write the sorted results here */
){
Vdbe *v = pParse->pVdbe; /* The prepared statement */
int addrBreak = sqlite3VdbeMakeLabel(v); /* Jump here to exit loop */
int addrContinue = sqlite3VdbeMakeLabel(v); /* Jump here for next cycle */
int addr;
int addrOnce = 0;
int iTab;
int pseudoTab = 0;
ExprList *pOrderBy = p->pOrderBy;
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
iTab = pOrderBy->iECursor;
regRow = sqlite3GetTempReg(pParse);
if( pSort->labelBkOut ){
sqlite3VdbeAddOp2(v, OP_Gosub, pSort->regReturn, pSort->labelBkOut);
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBreak);
sqlite3VdbeResolveLabel(v, pSort->labelBkOut);
}
iTab = pSort->iECursor;
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;
}
if( p->selFlags & SF_UseSorter ){
nKey = pOrderBy->nExpr - pSort->nOBSat;
if( pSort->sortFlags & SORTFLAG_UseSorter ){
int regSortOut = ++pParse->nMem;
int ptab2 = pParse->nTab++;
sqlite3VdbeAddOp3(v, OP_OpenPseudo, ptab2, regSortOut, pOrderBy->nExpr+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, pOrderBy->nExpr+1, regRow);
sqlite3VdbeChangeP5(v, OPFLAG_CLEARCACHE);
p5 = OPFLAG_CLEARCACHE;
bSeq = 0;
}else{
addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v);
codeOffset(v, p->iOffset, addrContinue);
sqlite3VdbeAddOp3(v, OP_Column, iTab, pOrderBy->nExpr+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:
@@ -1122,17 +1237,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);
@@ -1142,21 +1249,20 @@ 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);
if( p->selFlags & SF_UseSorter ){
if( pSort->sortFlags & SORTFLAG_UseSorter ){
sqlite3VdbeAddOp2(v, OP_SorterNext, iTab, addr); VdbeCoverage(v);
}else{
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr); VdbeCoverage(v);
}
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);
}
}
/*
@@ -1834,7 +1940,7 @@ static void generateWithRecursiveQuery(
int regCurrent; /* Register holding Current table */
int iQueue; /* The Queue table */
int iDistinct = 0; /* To ensure unique results if UNION */
int eDest = SRT_Table; /* How to write to Queue */
int eDest = SRT_Fifo; /* How to write to Queue */
SelectDest destQueue; /* SelectDest targetting the Queue table */
int i; /* Loop counter */
int rc; /* Result code */
@@ -1866,13 +1972,13 @@ static void generateWithRecursiveQuery(
/* Allocate cursors numbers for Queue and Distinct. The cursor number for
** the Distinct table must be exactly one greater than Queue in order
** for the SRT_DistTable and SRT_DistQueue destinations to work. */
** for the SRT_DistFifo and SRT_DistQueue destinations to work. */
iQueue = pParse->nTab++;
if( p->op==TK_UNION ){
eDest = pOrderBy ? SRT_DistQueue : SRT_DistTable;
eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
iDistinct = pParse->nTab++;
}else{
eDest = pOrderBy ? SRT_Queue : SRT_Table;
eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
}
sqlite3SelectDestInit(&destQueue, eDest, iQueue);
@@ -1938,6 +2044,7 @@ static void generateWithRecursiveQuery(
sqlite3VdbeResolveLabel(v, addrBreak);
end_of_recursive_query:
sqlite3ExprListDelete(pParse->db, p->pOrderBy);
p->pOrderBy = pOrderBy;
p->pLimit = pLimit;
p->pOffset = pOffset;
@@ -4309,7 +4416,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
"argument");
pFunc->iDistinct = -1;
}else{
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0, 0);
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
(char*)pKeyInfo, P4_KEYINFO);
}
@@ -4464,12 +4571,11 @@ int sqlite3Select(
ExprList *pEList; /* List of columns to extract. */
SrcList *pTabList; /* List of tables to select from */
Expr *pWhere; /* The WHERE clause. May be NULL */
ExprList *pOrderBy; /* The ORDER BY clause. May be NULL */
ExprList *pGroupBy; /* The GROUP BY clause. May be NULL */
Expr *pHaving; /* The HAVING clause. May be NULL */
int rc = 1; /* Value to return from this function */
int addrSortIndex; /* Address of an OP_OpenEphemeral instruction */
DistinctCtx sDistinct; /* Info on how to code the DISTINCT keyword */
SortCtx sSort; /* Info on how to code the ORDER BY clause */
AggInfo sAggInfo; /* Information used by aggregate queries */
int iEnd; /* Address of the end of the query */
sqlite3 *db; /* The database connection */
@@ -4486,9 +4592,15 @@ int sqlite3Select(
if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1;
memset(&sAggInfo, 0, sizeof(sAggInfo));
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue );
assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue );
if( IgnorableOrderby(pDest) ){
assert(pDest->eDest==SRT_Exists || pDest->eDest==SRT_Union ||
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard);
pDest->eDest==SRT_Except || pDest->eDest==SRT_Discard ||
pDest->eDest==SRT_Queue || pDest->eDest==SRT_DistFifo ||
pDest->eDest==SRT_DistQueue || pDest->eDest==SRT_Fifo);
/* If ORDER BY makes no difference in the output then neither does
** DISTINCT so it can be removed too. */
sqlite3ExprListDelete(db, p->pOrderBy);
@@ -4496,7 +4608,8 @@ int sqlite3Select(
p->selFlags &= ~SF_Distinct;
}
sqlite3SelectPrep(pParse, p, 0);
pOrderBy = p->pOrderBy;
memset(&sSort, 0, sizeof(sSort));
sSort.pOrderBy = p->pOrderBy;
pTabList = p->pSrc;
pEList = p->pEList;
if( pParse->nErr || db->mallocFailed ){
@@ -4618,7 +4731,7 @@ int sqlite3Select(
pParse->nHeight -= sqlite3SelectExprHeight(p);
pTabList = p->pSrc;
if( !IgnorableOrderby(pDest) ){
pOrderBy = p->pOrderBy;
sSort.pOrderBy = p->pOrderBy;
}
}
pEList = p->pEList;
@@ -4645,9 +4758,9 @@ int sqlite3Select(
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
** to disable this optimization for testing purposes.
*/
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
if( sqlite3ExprListCompare(p->pGroupBy, sSort.pOrderBy, -1)==0
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
pOrderBy = 0;
sSort.pOrderBy = 0;
}
/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
@@ -4666,12 +4779,12 @@ int sqlite3Select(
** BY and DISTINCT, and an index or separate temp-table for the other.
*/
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
&& sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
&& sqlite3ExprListCompare(sSort.pOrderBy, p->pEList, -1)==0
){
p->selFlags &= ~SF_Distinct;
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
pGroupBy = p->pGroupBy;
pOrderBy = 0;
sSort.pOrderBy = 0;
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
** the sDistinct.isTnct is still set. Hence, isTnct represents the
** original setting of the SF_Distinct flag, not the current setting */
@@ -4685,16 +4798,17 @@ int sqlite3Select(
** we figure out that the sorting index is not needed. The addrSortIndex
** variable is used to facilitate that change.
*/
if( pOrderBy ){
if( sSort.pOrderBy ){
KeyInfo *pKeyInfo;
pKeyInfo = keyInfoFromExprList(pParse, pOrderBy, 0);
pOrderBy->iECursor = pParse->nTab++;
p->addrOpenEphm[2] = addrSortIndex =
pKeyInfo = keyInfoFromExprList(pParse, sSort.pOrderBy, 0, 0);
sSort.iECursor = pParse->nTab++;
sSort.addrSortIndex =
sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
pOrderBy->iECursor, pOrderBy->nExpr+2, 0,
(char*)pKeyInfo, P4_KEYINFO);
sSort.iECursor, sSort.pOrderBy->nExpr+1+pEList->nExpr, 0,
(char*)pKeyInfo, P4_KEYINFO
);
}else{
addrSortIndex = -1;
sSort.addrSortIndex = -1;
}
/* If the output is destined for a temporary table, open that table.
@@ -4708,9 +4822,9 @@ int sqlite3Select(
iEnd = sqlite3VdbeMakeLabel(v);
p->nSelectRow = LARGEST_INT64;
computeLimitRegisters(pParse, p, iEnd);
if( p->iLimit==0 && addrSortIndex>=0 ){
sqlite3VdbeGetOp(v, addrSortIndex)->opcode = OP_SorterOpen;
p->selFlags |= SF_UseSorter;
if( p->iLimit==0 && sSort.addrSortIndex>=0 ){
sqlite3VdbeGetOp(v, sSort.addrSortIndex)->opcode = OP_SorterOpen;
sSort.sortFlags |= SORTFLAG_UseSorter;
}
/* Open a virtual index to use for the distinct set.
@@ -4719,7 +4833,7 @@ int sqlite3Select(
sDistinct.tabTnct = pParse->nTab++;
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
sDistinct.tabTnct, 0, 0,
(char*)keyInfoFromExprList(pParse, p->pEList, 0),
(char*)keyInfoFromExprList(pParse, p->pEList,0,0),
P4_KEYINFO);
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
@@ -4732,8 +4846,8 @@ int sqlite3Select(
u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
/* Begin the database scan. */
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pOrderBy, p->pEList,
wctrlFlags, 0);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
p->pEList, wctrlFlags, 0);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){
p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo);
@@ -4741,19 +4855,23 @@ int sqlite3Select(
if( sDistinct.isTnct && sqlite3WhereIsDistinct(pWInfo) ){
sDistinct.eTnctType = sqlite3WhereIsDistinct(pWInfo);
}
if( pOrderBy && sqlite3WhereIsOrdered(pWInfo) ) pOrderBy = 0;
if( sSort.pOrderBy ){
sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
sSort.pOrderBy = 0;
}
}
/* If sorting index that was created by a prior OP_OpenEphemeral
** instruction ended up not being needed, then change the OP_OpenEphemeral
** into an OP_Noop.
*/
if( addrSortIndex>=0 && pOrderBy==0 ){
sqlite3VdbeChangeToNoop(v, addrSortIndex);
p->addrOpenEphm[2] = -1;
if( sSort.addrSortIndex>=0 && sSort.pOrderBy==0 ){
sqlite3VdbeChangeToNoop(v, sSort.addrSortIndex);
}
/* Use the standard inner loop. */
selectInnerLoop(pParse, p, pEList, -1, pOrderBy, &sDistinct, pDest,
selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct, pDest,
sqlite3WhereContinueLabel(pWInfo),
sqlite3WhereBreakLabel(pWInfo));
@@ -4806,10 +4924,10 @@ 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, pOrderBy);
sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy);
if( pHaving ){
sqlite3ExprAnalyzeAggregates(&sNC, pHaving);
}
@@ -4843,7 +4961,7 @@ int sqlite3Select(
** will be converted into a Noop.
*/
sAggInfo.sortingIdx = pParse->nTab++;
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0);
pKeyInfo = keyInfoFromExprList(pParse, pGroupBy, 0, 0);
addrSortingIdx = sqlite3VdbeAddOp4(v, OP_SorterOpen,
sAggInfo.sortingIdx, sAggInfo.nSortingColumn,
0, (char*)pKeyInfo, P4_KEYINFO);
@@ -4872,10 +4990,10 @@ int sqlite3Select(
** in the right order to begin with.
*/
sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset);
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0,
WHERE_GROUPBY, 0);
if( pWInfo==0 ) goto select_end;
if( sqlite3WhereIsOrdered(pWInfo) ){
if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){
/* The optimizer is able to deliver rows in group by order so
** we do not have to sort. The OP_OpenEphemeral table will be
** cancelled later because we still need to use the pKeyInfo
@@ -4898,8 +5016,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++;
@@ -4909,8 +5027,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 ){
@@ -5026,7 +5143,7 @@ int sqlite3Select(
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
finalizeAggFunctions(pParse, &sAggInfo);
sqlite3ExprIfFalse(pParse, pHaving, addrOutputRow+1, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, -1, pOrderBy,
selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
&sDistinct, pDest,
addrOutputRow+1, addrSetAbort);
sqlite3VdbeAddOp1(v, OP_Return, regOutputRow);
@@ -5158,7 +5275,7 @@ int sqlite3Select(
}
updateAccumulator(pParse, &sAggInfo);
assert( pMinMax==0 || pMinMax->nExpr==1 );
if( sqlite3WhereIsOrdered(pWInfo) ){
if( sqlite3WhereIsOrdered(pWInfo)>0 ){
sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3WhereBreakLabel(pWInfo));
VdbeComment((v, "%s() by index",
(flag==WHERE_ORDERBY_MIN?"min":"max")));
@@ -5167,7 +5284,7 @@ int sqlite3Select(
finalizeAggFunctions(pParse, &sAggInfo);
}
pOrderBy = 0;
sSort.pOrderBy = 0;
sqlite3ExprIfFalse(pParse, pHaving, addrEnd, SQLITE_JUMPIFNULL);
selectInnerLoop(pParse, p, p->pEList, -1, 0, 0,
pDest, addrEnd, addrEnd);
@@ -5184,9 +5301,9 @@ int sqlite3Select(
/* If there is an ORDER BY clause, then we need to sort the results
** and send them to the callback one by one.
*/
if( pOrderBy ){
explainTempTable(pParse, "ORDER BY");
generateSortTail(pParse, p, v, pEList->nExpr, pDest);
if( sSort.pOrderBy ){
explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY");
generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
}
/* Jump here to skip this query
+6 -2
View File
@@ -1195,7 +1195,8 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
int iOp; /* Index of operation in p->aiIndent[] */
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
"NextIfOpen", "PrevIfOpen", 0 };
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", "Rewind", 0 };
const char *azGoto[] = { "Goto", 0 };
@@ -2129,10 +2130,12 @@ static void tryToClone(struct callback_data *p, const char *zNewDb){
fprintf(stderr, "Cannot create output database: %s\n",
sqlite3_errmsg(newDb));
}else{
sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0);
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
tryToCloneSchema(p, newDb, "type!='table'", 0);
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
sqlite3_close(newDb);
}
@@ -3531,7 +3534,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);
}
/*
+13 -1
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
@@ -6118,7 +6129,8 @@ int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_LAST 21
#define SQLITE_TESTCTRL_SORTER_MMAP 22
#define SQLITE_TESTCTRL_LAST 22
/*
** CAPI3REF: SQLite Runtime Status
+55 -23
View File
@@ -422,6 +422,19 @@
# 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
/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
@@ -788,6 +801,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;
@@ -967,6 +981,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 */
@@ -1627,6 +1642,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 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) */
@@ -1893,8 +1909,8 @@ struct Expr {
#define EP_VarSelect 0x000020 /* pSelect is correlated, not constant */
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
/* unused 0x000200 */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE operator */
#define EP_Generic 0x000200 /* Ignore COLLATE or affinity on this tree */
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
@@ -1958,7 +1974,6 @@ struct Expr {
*/
struct ExprList {
int nExpr; /* Number of expressions on the list */
int iECursor; /* VDBE Cursor associated with this ExprList */
struct ExprList_item { /* For each expression in the list */
Expr *pExpr; /* The list of expressions */
char *zName; /* Token associated with this expression */
@@ -2182,7 +2197,7 @@ struct Select {
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
u16 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
int addrOpenEphm[3]; /* OP_OpenEphem opcodes related to this select */
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
u64 nSelectRow; /* Estimated number of result rows */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
@@ -2206,9 +2221,9 @@ struct Select {
#define SF_UsesEphemeral 0x0008 /* Uses the OpenEphemeral opcode */
#define SF_Expanded 0x0010 /* sqlite3SelectExpand() called on this */
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
#define SF_UseSorter 0x0040 /* Sort using a sorter */
/* 0x0040 NOT USED */
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
#define SF_Materialize 0x0100 /* NOT USED */
/* 0x0100 NOT USED */
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
@@ -2261,13 +2276,15 @@ struct Select {
** starting with pDest->iSdst.
**
** SRT_Table Store results in temporary table pDest->iSDParm.
** This is like SRT_EphemTab except that the table
** is assumed to already be open.
** SRT_Fifo This is like SRT_EphemTab except that the table
** is assumed to already be open. SRT_Fifo has
** the additional property of being able to ignore
** the ORDER BY clause.
**
** SRT_DistTable Store results in a temporary table pDest->iSDParm.
** SRT_DistFifo Store results in a temporary table pDest->iSDParm.
** But also use temporary table pDest->iSDParm+1 as
** a record of all prior results and ignore any duplicate
** rows. Name means: "Distinct Table".
** rows. Name means: "Distinct Fifo".
**
** SRT_Queue Store results in priority queue pDest->iSDParm (really
** an index). Append a sequence number so that all entries
@@ -2281,19 +2298,20 @@ struct Select {
#define SRT_Except 2 /* Remove result from a UNION index */
#define SRT_Exists 3 /* Store 1 if the result is not empty */
#define SRT_Discard 4 /* Do not save the results anywhere */
#define SRT_Fifo 5 /* Store result as data with an automatic rowid */
#define SRT_DistFifo 6 /* Like SRT_Fifo, but unique results only */
#define SRT_Queue 7 /* Store result in an queue */
#define SRT_DistQueue 8 /* Like SRT_Queue, but unique results only */
/* The ORDER BY clause is ignored for all of the above */
#define IgnorableOrderby(X) ((X->eDest)<=SRT_Discard)
#define IgnorableOrderby(X) ((X->eDest)<=SRT_DistQueue)
#define SRT_Output 5 /* Output each row of result */
#define SRT_Mem 6 /* Store result in a memory cell */
#define SRT_Set 7 /* Store results as keys in an index */
#define SRT_EphemTab 8 /* Create transient tab and store like SRT_Table */
#define SRT_Coroutine 9 /* Generate a single row of result */
#define SRT_Table 10 /* Store result as data with an automatic rowid */
#define SRT_DistTable 11 /* Like SRT_Table, but unique results only */
#define SRT_Queue 12 /* Store result in an queue */
#define SRT_DistQueue 13 /* Like SRT_Queue, but unique results only */
#define SRT_Output 9 /* Output each row of result */
#define SRT_Mem 10 /* Store result in a memory cell */
#define SRT_Set 11 /* Store results as keys in an index */
#define SRT_EphemTab 12 /* Create transient tab and store like SRT_Table */
#define SRT_Coroutine 13 /* Generate a single row of result */
#define SRT_Table 14 /* Store result as data with an automatic rowid */
/*
** An instance of this object describes where to put of the results of
@@ -2391,8 +2409,6 @@ struct Parse {
u8 checkSchema; /* Causes schema cookie check after an error */
u8 nested; /* Number of nested calls to the parser/code generator */
u8 nTempReg; /* Number of temporary registers in aTempReg[] */
u8 nColCache; /* Number of entries in aColCache[] */
u8 iColCache; /* Next entry in aColCache[] to replace */
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
u8 mayAbort; /* True if statement may throw an ABORT exception */
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
@@ -2683,6 +2699,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 */
@@ -3291,7 +3308,7 @@ int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, Token*);
Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*);
Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*);
Expr *sqlite3ExprSkipCollate(Expr*);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
@@ -3632,4 +3649,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_ */
+55
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);
@@ -6481,6 +6535,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 },
+6
View File
@@ -99,6 +99,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "mmap", "0", TCL_GLOBAL_ONLY);
#endif
#if SQLITE_MAX_WORKER_THREADS>0
Tcl_SetVar2(interp, "sqlite_options", "worker_threads", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "worker_threads", "0", TCL_GLOBAL_ONLY);
#endif
#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 },
+48 -1
View File
@@ -67,6 +67,11 @@
** test_syscall list
** Return a list of all system calls. The list is constructed using
** the xNextSystemCall() VFS method.
**
** test_syscall pagesize PGSZ
** If PGSZ is a power of two greater than 256, install a wrapper around
** OS function getpagesize() that reports the system page size as PGSZ.
** Or, if PGSZ is less than zero, remove any wrapper already installed.
*/
#include "sqliteInt.h"
@@ -89,7 +94,9 @@ static struct TestSyscallGlobal {
int bPersist; /* 1 for persistent errors, 0 for transient */
int nCount; /* Fail after this many more calls */
int nFail; /* Number of failures that have occurred */
} gSyscall = { 0, 0 };
int pgsz;
sqlite3_syscall_ptr orig_getpagesize;
} gSyscall = { 0, 0, 0, 0, 0 };
static int ts_open(const char *, int, int);
static int ts_close(int fd);
@@ -650,6 +657,45 @@ static int test_syscall_defaultvfs(
return TCL_OK;
}
static int ts_getpagesize(void){
return gSyscall.pgsz;
}
static int test_syscall_pagesize(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
int pgsz;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "PGSZ");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[2], &pgsz) ){
return TCL_ERROR;
}
if( pgsz<0 ){
if( gSyscall.orig_getpagesize ){
pVfs->xSetSystemCall(pVfs, "getpagesize", gSyscall.orig_getpagesize);
}
}else{
if( pgsz<512 || (pgsz & (pgsz-1)) ){
Tcl_AppendResult(interp, "pgsz out of range", 0);
return TCL_ERROR;
}
gSyscall.orig_getpagesize = pVfs->xGetSystemCall(pVfs, "getpagesize");
gSyscall.pgsz = pgsz;
pVfs->xSetSystemCall(
pVfs, "getpagesize", (sqlite3_syscall_ptr)ts_getpagesize
);
}
return TCL_OK;
}
static int test_syscall(
void * clientData,
Tcl_Interp *interp,
@@ -668,6 +714,7 @@ static int test_syscall(
{ "exists", test_syscall_exists },
{ "list", test_syscall_list },
{ "defaultvfs", test_syscall_defaultvfs },
{ "pagesize", test_syscall_pagesize },
{ 0, 0 }
};
int iCmd;
+220
View File
@@ -0,0 +1,220 @@
/*
** 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;
int done;
void *pOut;
};
/* 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));
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);
return SQLITE_OK;
}
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
/****************************** End Single-Threaded *************************/
#endif /* SQLITE_MAX_WORKER_THREADS>0 */
+1 -1
View File
@@ -566,7 +566,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
assert( pTable!=0 );
if( (v = sqlite3GetVdbe(pParse))!=0 ){
int base;
static const int iLn = __LINE__+2;
static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
{ OP_String8, 0, 1, 0}, /* 1 */
+88 -14
View File
@@ -310,6 +310,29 @@ void sqlite3ValueApplyAffinity(
applyAffinity((Mem *)pVal, affinity, enc);
}
/*
** Return the numeric type for pMem, either MEM_Int or MEM_Real or both or
** none.
**
** Unlike applyNumericAffinity(), this routine does not modify pMem->flags.
** But it does set pMem->r and pMem->u.i appropriately.
*/
static u16 numericType(Mem *pMem){
if( pMem->flags & (MEM_Int|MEM_Real) ){
return pMem->flags & (MEM_Int|MEM_Real);
}
if( pMem->flags & (MEM_Str|MEM_Blob) ){
if( sqlite3AtoF(pMem->z, &pMem->r, pMem->n, pMem->enc)==0 ){
return 0;
}
if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){
return MEM_Int;
}
return MEM_Real;
}
return 0;
}
#ifdef SQLITE_DEBUG
/*
** Write a nice string representation of the contents of cell pMem
@@ -1080,10 +1103,11 @@ case OP_Variable: { /* out2-prerelease */
/* Opcode: Move P1 P2 P3 * *
** Synopsis: r[P2@P3]=r[P1@P3]
**
** Move the values in register P1..P1+P3 over into
** registers P2..P2+P3. Registers P1..P1+P3 are
** Move the P3 values in register P1..P1+P3-1 over into
** registers P2..P2+P3-1. Registers P1..P1+P3-1 are
** left holding a NULL. It is an error for register ranges
** P1..P1+P3 and P2..P2+P3 to overlap.
** P1..P1+P3-1 and P2..P2+P3-1 to overlap. It is an error
** for P3 to be less than 1.
*/
case OP_Move: {
char *zMalloc; /* Holding variable for allocated memory */
@@ -1094,7 +1118,7 @@ case OP_Move: {
n = pOp->p3;
p1 = pOp->p1;
p2 = pOp->p2;
assert( n>=0 && p1>0 && p2>0 );
assert( n>0 && p1>0 && p2>0 );
assert( p1+n<=p2 || p2+n<=p1 );
pIn1 = &aMem[p1];
@@ -1118,7 +1142,7 @@ case OP_Move: {
REGISTER_TRACE(p2++, pOut);
pIn1++;
pOut++;
}while( n-- );
}while( --n );
break;
}
@@ -1350,20 +1374,22 @@ case OP_Multiply: /* same as TK_STAR, in1, in2, out3 */
case OP_Divide: /* same as TK_SLASH, in1, in2, out3 */
case OP_Remainder: { /* same as TK_REM, in1, in2, out3 */
char bIntint; /* Started out as two integer operands */
int flags; /* Combined MEM_* flags from both inputs */
u16 flags; /* Combined MEM_* flags from both inputs */
u16 type1; /* Numeric type of left operand */
u16 type2; /* Numeric type of right operand */
i64 iA; /* Integer value of left operand */
i64 iB; /* Integer value of right operand */
double rA; /* Real value of left operand */
double rB; /* Real value of right operand */
pIn1 = &aMem[pOp->p1];
applyNumericAffinity(pIn1);
type1 = numericType(pIn1);
pIn2 = &aMem[pOp->p2];
applyNumericAffinity(pIn2);
type2 = numericType(pIn2);
pOut = &aMem[pOp->p3];
flags = pIn1->flags | pIn2->flags;
if( (flags & MEM_Null)!=0 ) goto arithmetic_result_is_null;
if( (pIn1->flags & pIn2->flags & MEM_Int)==MEM_Int ){
if( (type1 & type2 & MEM_Int)!=0 ){
iA = pIn1->u.i;
iB = pIn2->u.i;
bIntint = 1;
@@ -1419,7 +1445,7 @@ fp_math:
}
pOut->r = rB;
MemSetTypeFlag(pOut, MEM_Real);
if( (flags & MEM_Real)==0 && !bIntint ){
if( ((type1|type2)&MEM_Real)==0 && !bIntint ){
sqlite3VdbeIntegerAffinity(pOut);
}
#endif
@@ -1995,6 +2021,7 @@ case OP_Permutation: {
}
/* Opcode: Compare P1 P2 P3 P4 P5
** Synopsis: r[P1@P3] <-> r[P2@P3]
**
** Compare two vectors of registers in reg(P1)..reg(P1+P3-1) (call this
** vector "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of
@@ -3330,6 +3357,7 @@ case OP_OpenEphemeral: {
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->isEphemeral = 1;
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
if( rc==SQLITE_OK ){
@@ -3362,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;
@@ -3378,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;
}
@@ -3820,7 +3870,7 @@ case OP_NotExists: { /* jump, in3 */
}
/* Opcode: Sequence P1 P2 * * *
** Synopsis: r[P2]=rowid
** Synopsis: r[P2]=cursor[P1].ctr++
**
** Find the next available sequence number for cursor P1.
** Write the sequence number into register P2.
@@ -4511,6 +4561,7 @@ case OP_SorterNext: { /* jump */
pC = p->apCsr[pOp->p1];
assert( isSorter(pC) );
res = 0;
rc = sqlite3VdbeSorterNext(db, pC, &res);
goto next_tail;
case OP_PrevIfOpen: /* jump */
@@ -4869,6 +4920,29 @@ case OP_Clear: {
break;
}
/* Opcode: ResetSorter P1 * * * *
**
** Delete all contents from the ephemeral table or sorter
** that is open on cursor P1.
**
** This opcode only works for cursors used for sorting and
** opened with OP_OpenEphemeral or OP_SorterOpen.
*/
case OP_ResetSorter: {
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
if( pC->pSorter ){
sqlite3VdbeSorterReset(db, pC->pSorter);
}else{
assert( pC->isEphemeral );
rc = sqlite3BtreeClearTableOfCursor(pC->pCursor);
}
break;
}
/* Opcode: CreateTable P1 P2 * * *
** Synopsis: r[P2]=root iDb=P1
**
@@ -5877,7 +5951,7 @@ case OP_VOpen: {
#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VFilter P1 P2 P3 P4 *
** Synopsis: iPlan=r[P3] zPlan='P4'
** Synopsis: iplan=r[P3] zplan='P4'
**
** P1 is a cursor opened using VOpen. P2 is an address to jump to if
** the filtered result set is empty.
+4 -2
View File
@@ -211,10 +211,10 @@ void sqlite3VdbeSetVarmask(Vdbe*, int);
#endif
void sqlite3VdbeRecordUnpack(KeyInfo*,int,const void*,UnpackedRecord*);
int sqlite3VdbeRecordCompare(int,const void*,const UnpackedRecord*,int);
int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*,int);
UnpackedRecord *sqlite3VdbeAllocUnpackedRecord(KeyInfo *, char *, int, char **);
typedef int (*RecordCompare)(int,const void*,const UnpackedRecord*,int);
typedef int (*RecordCompare)(int,const void*,UnpackedRecord*,int);
RecordCompare sqlite3VdbeFindCompare(UnpackedRecord*);
#ifndef SQLITE_OMIT_TRIGGER
@@ -272,11 +272,13 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
#else
# define VdbeCoverage(v)
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
# define VDBE_OFFSET_LINENO(x) 0
#endif
#endif
+4 -2
View File
@@ -72,6 +72,7 @@ struct VdbeCursor {
u8 nullRow; /* True if pointing to a row with no data */
u8 rowidIsValid; /* True if lastRowid is valid */
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
Bool isEphemeral:1; /* True for an ephemeral table */
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
Bool isTable:1; /* True if a table requiring integer keys */
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
@@ -391,7 +392,7 @@ u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,const UnpackedRecord*,int*);
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite3VdbeExec(Vdbe*);
@@ -436,7 +437,8 @@ 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 *);
+37 -13
View File
@@ -783,7 +783,9 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
addr = p->nOp - 1;
}
pOp = &p->aOp[addr];
assert( pOp->p4type==P4_NOTUSED || pOp->p4type==P4_INT32 );
assert( pOp->p4type==P4_NOTUSED
|| pOp->p4type==P4_INT32
|| pOp->p4type==P4_KEYINFO );
freeP4(db, pOp->p4type, pOp->p4.p);
pOp->p4.p = 0;
if( n==P4_INT32 ){
@@ -2733,7 +2735,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
if( rc ) return rc;
if( hasMoved ){
p->cacheStatus = CACHE_STALE;
p->nullRow = 1;
if( hasMoved==2 ) p->nullRow = 1;
}
}
return SQLITE_OK;
@@ -3227,7 +3229,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
@@ -3250,6 +3253,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;
}
}
@@ -3332,7 +3336,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(). */
@@ -3403,10 +3407,15 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
** Key1 and Key2 do not have to contain the same number of fields. If all
** fields that appear in both keys are equal, then pPKey2->default_rc is
** returned.
**
** 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 */
const UnpackedRecord *pPKey2, /* Right key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* If true, skip the first field */
){
u32 d1; /* Offset into aKey[] of next data element */
@@ -3432,6 +3441,10 @@ int sqlite3VdbeRecordCompare(
}else{
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
if( d1>(unsigned)nKey1 ){
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
i = 0;
}
@@ -3508,13 +3521,16 @@ int sqlite3VdbeRecordCompare(
testcase( (d1+mem1.n)==(unsigned)nKey1 );
testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
if( (d1+mem1.n) > (unsigned)nKey1 ){
rc = 1; /* Corruption */
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);
@@ -3534,7 +3550,8 @@ int sqlite3VdbeRecordCompare(
testcase( (d1+nStr)==(unsigned)nKey1 );
testcase( (d1+nStr+1)==(unsigned)nKey1 );
if( (d1+nStr) > (unsigned)nKey1 ){
rc = 1; /* Corruption */
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}else{
int nCmp = MIN(nStr, pRhs->n);
rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
@@ -3553,7 +3570,7 @@ int sqlite3VdbeRecordCompare(
if( pKeyInfo->aSortOrder[i] ){
rc = -rc;
}
assert( CORRUPT_DB
assert( CORRUPT_DB || pKeyInfo->db==0
|| (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
|| (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
|| pKeyInfo->db->mallocFailed
@@ -3587,10 +3604,13 @@ int sqlite3VdbeRecordCompare(
** that (a) the first field of pPKey2 is an integer, and (b) the
** size-of-header varint at the start of (pKey1/nKey1) fits in a single
** byte (i.e. is less than 128).
**
** To avoid concerns about buffer overreads, this routine is only used
** on schemas where the maximum valid header size is 63 bytes or less.
*/
static int vdbeRecordCompareInt(
int nKey1, const void *pKey1, /* Left key */
const UnpackedRecord *pPKey2, /* Right key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip /* Ignored */
){
const u8 *aKey = &((const u8*)pKey1)[*(const u8*)pKey1 & 0x3F];
@@ -3603,6 +3623,7 @@ static int vdbeRecordCompareInt(
UNUSED_PARAMETER(bSkip);
assert( bSkip==0 );
assert( (*(u8*)pKey1)<=0x3F || CORRUPT_DB );
switch( serial_type ){
case 1: { /* 1-byte signed integer */
lhs = ONE_BYTE_INT(aKey);
@@ -3687,7 +3708,7 @@ static int vdbeRecordCompareInt(
*/
static int vdbeRecordCompareString(
int nKey1, const void *pKey1, /* Left key */
const UnpackedRecord *pPKey2, /* Right key */
UnpackedRecord *pPKey2, /* Right key */
int bSkip
){
const u8 *aKey1 = (const u8*)pKey1;
@@ -3708,7 +3729,10 @@ static int vdbeRecordCompareString(
int szHdr = aKey1[0];
nStr = (serial_type-12) / 2;
if( (szHdr + nStr) > nKey1 ) return 0; /* Corruption */
if( (szHdr + nStr) > nKey1 ){
pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
return 0; /* Corruption */
}
nCmp = MIN( pPKey2->aMem[0].n, nStr );
res = memcmp(&aKey1[szHdr], pPKey2->aMem[0].z, nCmp);
@@ -3873,7 +3897,7 @@ idx_rowid_corruption:
*/
int sqlite3VdbeIdxKeyCompare(
VdbeCursor *pC, /* The cursor to compare against */
const UnpackedRecord *pUnpacked, /* Unpacked version of key */
UnpackedRecord *pUnpacked, /* Unpacked version of key */
int *res /* Write the comparison result here */
){
i64 nCellKey = 0;
+1 -1
View File
@@ -133,7 +133,7 @@ int sqlite3_blob_open(
** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const int iLn = __LINE__+4;
static const int iLn = VDBE_OFFSET_LINENO(4);
static const VdbeOpList openBlob[] = {
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
+1198 -451
View File
File diff suppressed because it is too large Load Diff
+281 -149
View File
@@ -39,7 +39,7 @@ int sqlite3WhereIsDistinct(WhereInfo *pWInfo){
** Return FALSE if the output needs to be sorted.
*/
int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
return pWInfo->bOBSat!=0;
return pWInfo->nOBSat;
}
/*
@@ -47,6 +47,7 @@ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
** immediately with the next row of a WHERE clause.
*/
int sqlite3WhereContinueLabel(WhereInfo *pWInfo){
assert( pWInfo->iContinue!=0 );
return pWInfo->iContinue;
}
@@ -3036,8 +3037,11 @@ static Bitmask codeOneLoopStart(
** the first one after the nEq equality constraints in the index,
** this requires some special handling.
*/
assert( pWInfo->pOrderBy==0
|| pWInfo->pOrderBy->nExpr==1
|| (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)==0 );
if( (pWInfo->wctrlFlags&WHERE_ORDERBY_MIN)!=0
&& (pWInfo->bOBSat!=0)
&& pWInfo->nOBSat>0
&& (pIdx->nKeyCol>nEq)
){
assert( pLoop->u.btree.nSkip==0 );
@@ -3208,8 +3212,7 @@ static Bitmask codeOneLoopStart(
pLevel->op = OP_Next;
}
pLevel->p1 = iIdxCur;
assert( (WHERE_UNQ_WANTED>>16)==1 );
pLevel->p3 = (pLoop->wsFlags>>16)&1;
pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0;
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
}else{
@@ -3708,6 +3711,124 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
}
}
/*
** Return TRUE if the set of WHERE clause terms used by pA is a proper
** subset of the WHERE clause terms used by pB.
*/
static int whereLoopProperSubset(const WhereLoop *pA, const WhereLoop *pB){
int i, j;
assert( pA->nLTerm<pB->nLTerm ); /* Checked by calling function */
for(j=0, i=pA->nLTerm-1; i>=0 && j>=0; i--){
for(j=pB->nLTerm-1; j>=0; j--){
if( pB->aLTerm[j]==pA->aLTerm[i] ) break;
}
}
return j>=0;
}
/*
** Try to adjust the cost of WhereLoop pTemplate upwards or downwards so
** that:
**
** (1) pTemplate costs less than any other WhereLoops that are a proper
** subset of pTemplate
**
** (2) pTemplate costs more than any other WhereLoops for which pTemplate
** is a proper subset.
**
** 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.
*/
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
for(; p; p=p->pNextLoop){
if( p->iTab!=pTemplate->iTab ) continue;
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
if( p->nLTerm<pTemplate->nLTerm
&& (p->rRun<pTemplate->rRun || (p->rRun==pTemplate->rRun &&
p->nOut<=pTemplate->nOut))
&& whereLoopProperSubset(p, pTemplate)
){
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut - 1;
}else
if( p->nLTerm>pTemplate->nLTerm
&& (p->rRun>pTemplate->rRun || (p->rRun==pTemplate->rRun &&
p->nOut>=pTemplate->nOut))
&& whereLoopProperSubset(pTemplate, p)
){
pTemplate->rRun = p->rRun;
pTemplate->nOut = p->nOut + 1;
}
}
}
/*
** Search the list of WhereLoops in *ppPrev looking for one that can be
** supplanted by pTemplate.
**
** Return NULL if the WhereLoop list contains an entry that can supplant
** pTemplate, in other words if pTemplate does not belong on the list.
**
** If pX is a WhereLoop that pTemplate can supplant, then return the
** link that points to pX.
**
** If pTemplate cannot supplant any existing element of the list but needs
** to be added to the list, then return a pointer to the tail of the list.
*/
static WhereLoop **whereLoopFindLesser(
WhereLoop **ppPrev,
const WhereLoop *pTemplate
){
WhereLoop *p;
for(p=(*ppPrev); p; ppPrev=&p->pNextLoop, p=*ppPrev){
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
/* If either the iTab or iSortIdx values for two WhereLoop are different
** then those WhereLoops need to be considered separately. Neither is
** a candidate to replace the other. */
continue;
}
/* In the current implementation, the rSetup value is either zero
** or the cost of building an automatic index (NlogN) and the NlogN
** is the same for compatible WhereLoops. */
assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
/* If existing WhereLoop p is better than pTemplate, pTemplate can be
** discarded. WhereLoop p is better if:
** (1) p has no more dependencies than pTemplate, and
** (2) p has an equal or lower cost than pTemplate
*/
if( (p->prereq & pTemplate->prereq)==p->prereq /* (1) */
&& p->rSetup<=pTemplate->rSetup /* (2a) */
&& p->rRun<=pTemplate->rRun /* (2b) */
&& p->nOut<=pTemplate->nOut /* (2c) */
){
return 0; /* Discard pTemplate */
}
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
** (1) pTemplate has no more dependences than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
&& p->rRun>=pTemplate->rRun /* (2a) */
&& p->nOut>=pTemplate->nOut /* (2b) */
){
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
break; /* Cause p to be overwritten by pTemplate */
}
}
return ppPrev;
}
/*
** Insert or replace a WhereLoop entry using the template supplied.
**
@@ -3717,25 +3838,23 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
** fewer dependencies than the template. Otherwise a new WhereLoop is
** added based on the template.
**
** If pBuilder->pOrSet is not NULL then we only care about only the
** If pBuilder->pOrSet is not NULL then we care about only the
** prerequisites and rRun and nOut costs of the N best loops. That
** information is gathered in the pBuilder->pOrSet object. This special
** processing mode is used only for OR clause processing.
**
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
** still might overwrite similar loops with the new template if the
** template is better. Loops may be overwritten if the following
** new template is better. Loops may be overwritten if the following
** conditions are met:
**
** (1) They have the same iTab.
** (2) They have the same iSortIdx.
** (3) The template has same or fewer dependencies than the current loop
** (4) The template has the same or lower cost than the current loop
** (5) The template uses more terms of the same index but has no additional
** dependencies
*/
static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
WhereLoop **ppPrev, *p, *pNext = 0;
WhereLoop **ppPrev, *p;
WhereInfo *pWInfo = pBuilder->pWInfo;
sqlite3 *db = pWInfo->pParse->db;
@@ -3758,64 +3877,23 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
return SQLITE_OK;
}
/* Search for an existing WhereLoop to overwrite, or which takes
** priority over pTemplate.
/* Look for an existing WhereLoop to replace with pTemplate
*/
for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){
if( p->iTab!=pTemplate->iTab || p->iSortIdx!=pTemplate->iSortIdx ){
/* If either the iTab or iSortIdx values for two WhereLoop are different
** then those WhereLoops need to be considered separately. Neither is
** a candidate to replace the other. */
continue;
}
/* In the current implementation, the rSetup value is either zero
** or the cost of building an automatic index (NlogN) and the NlogN
** is the same for compatible WhereLoops. */
assert( p->rSetup==0 || pTemplate->rSetup==0
|| p->rSetup==pTemplate->rSetup );
whereLoopAdjustCost(pWInfo->pLoops, pTemplate);
ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate);
/* whereLoopAddBtree() always generates and inserts the automatic index
** case first. Hence compatible candidate WhereLoops never have a larger
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
if( (p->prereq & pTemplate->prereq)==p->prereq
&& p->rSetup<=pTemplate->rSetup
&& p->rRun<=pTemplate->rRun
&& p->nOut<=pTemplate->nOut
){
/* This branch taken when p is equal or better than pTemplate in
** all of (1) dependencies (2) setup-cost, (3) run-cost, and
** (4) number of output rows. */
assert( p->rSetup==pTemplate->rSetup );
if( p->prereq==pTemplate->prereq
&& p->nLTerm<pTemplate->nLTerm
&& (p->wsFlags & pTemplate->wsFlags & WHERE_INDEXED)!=0
&& (p->u.btree.pIndex==pTemplate->u.btree.pIndex
|| pTemplate->rRun+p->nLTerm<=p->rRun+pTemplate->nLTerm)
){
/* Overwrite an existing WhereLoop with an similar one that uses
** more terms of the index */
pNext = p->pNextLoop;
break;
}else{
/* pTemplate is not helpful.
** Return without changing or adding anything */
goto whereLoopInsert_noop;
}
}
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
&& p->rRun>=pTemplate->rRun
&& p->nOut>=pTemplate->nOut
){
/* Overwrite an existing WhereLoop with a better one: one that is
** better at one of (1) dependencies, (2) setup-cost, (3) run-cost
** or (4) number of output rows, and is no worse in any of those
** categories. */
assert( p->rSetup>=pTemplate->rSetup ); /* SETUP-INVARIANT above */
pNext = p->pNextLoop;
break;
if( ppPrev==0 ){
/* There already exists a WhereLoop on the list that is better
** than pTemplate, so just ignore pTemplate */
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-noop: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
}else{
p = *ppPrev;
}
/* If we reach this point it means that either p[] should be overwritten
@@ -3833,13 +3911,33 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}
#endif
if( p==0 ){
p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
/* Allocate a new WhereLoop to add to the end of the list */
*ppPrev = p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
if( p==0 ) return SQLITE_NOMEM;
whereLoopInit(p);
p->pNextLoop = 0;
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
** p[] that are also supplated by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
ppTail = whereLoopFindLesser(ppTail, pTemplate);
if( NEVER(ppTail==0) ) break;
pToDel = *ppTail;
if( pToDel==0 ) break;
*ppTail = pToDel->pNextLoop;
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-del: ");
whereLoopPrint(pToDel, pBuilder->pWC);
}
#endif
whereLoopDelete(db, pToDel);
}
}
whereLoopXfer(db, p, pTemplate);
p->pNextLoop = pNext;
*ppPrev = p;
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
Index *pIndex = p->u.btree.pIndex;
if( pIndex && pIndex->tnum==0 ){
@@ -3847,16 +3945,6 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}
}
return SQLITE_OK;
/* Jump here if the insert is a no-op */
whereLoopInsert_noop:
#if WHERETRACE_ENABLED /* 0x8 */
if( sqlite3WhereTrace & 0x8 ){
sqlite3DebugPrintf("ins-noop: ");
whereLoopPrint(pTemplate, pBuilder->pWC);
}
#endif
return SQLITE_OK;
}
/*
@@ -3974,7 +4062,10 @@ static int whereLoopAddBtreeIndex(
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);
pNew->nOut = saved_nOut;
}
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
int nIn = 0;
@@ -4007,6 +4098,8 @@ static int whereLoopAddBtreeIndex(
/* "x IN (value, value, ...)" */
nIn = sqlite3LogEst(pExpr->x.pList->nExpr);
}
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;
@@ -4320,18 +4413,34 @@ 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 = sqlite3LogEstAdd(rSize,rLogSize) + 1 +
(15*pProbe->szIdxRow)/pTab->szTabRow;
pNew->rRun += 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
}else{
/* TUNING: Cost of scanning a non-covering index is (N+1)*log2(N)
** which we will simplify to just N*log2(N) */
pNew->rRun = rSize + rLogSize;
/* 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;
}
whereLoopOutputAdjust(pWC, pNew);
rc = whereLoopInsert(pBuilder, pNew);
@@ -4503,8 +4612,8 @@ static int whereLoopAddVirtual(
pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr;
pIdxInfo->needToFreeIdxStr = 0;
pNew->u.vtab.idxStr = pIdxInfo->idxStr;
pNew->u.vtab.isOrdered = (u8)((pIdxInfo->nOrderBy!=0)
&& pIdxInfo->orderByConsumed);
pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ?
pIdxInfo->nOrderBy : 0);
pNew->rSetup = 0;
pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost);
pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows);
@@ -4665,11 +4774,11 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/*
** Examine a WherePath (with the addition of the extra WhereLoop of the 5th
** parameters) to see if it outputs rows in the requested ORDER BY
** (or GROUP BY) without requiring a separate sort operation. Return:
** (or GROUP BY) without requiring a separate sort operation. Return N:
**
** 0: ORDER BY is not satisfied. Sorting required
** 1: ORDER BY is satisfied. Omit sorting
** -1: Unknown at this time
** N>0: N terms of the ORDER BY clause are satisfied
** N==0: No terms of the ORDER BY clause are satisfied
** N<0: Unknown yet how many terms of ORDER BY might be satisfied.
**
** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as
** strict. With GROUP BY and DISTINCT the only requirement is that
@@ -4679,7 +4788,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
** the pOrderBy terms can be matched in any order. With ORDER BY, the
** pOrderBy terms must be matched in strict left-to-right order.
*/
static int wherePathSatisfiesOrderBy(
static i8 wherePathSatisfiesOrderBy(
WhereInfo *pWInfo, /* The WHERE clause */
ExprList *pOrderBy, /* ORDER BY or GROUP BY or DISTINCT clause to check */
WherePath *pPath, /* The WherePath to check */
@@ -4864,23 +4973,23 @@ static int wherePathSatisfiesOrderBy(
isMatch = 1;
break;
}
if( isMatch && (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */
if( revSet ){
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) isMatch = 0;
}else{
rev = revIdx ^ pOrderBy->a[i].sortOrder;
if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1;
}
}
if( isMatch ){
if( iColumn<0 ){
testcase( distinctColumns==0 );
distinctColumns = 1;
}
obSat |= MASKBIT(i);
if( (pWInfo->wctrlFlags & WHERE_GROUPBY)==0 ){
/* Make sure the sort order is compatible in an ORDER BY clause.
** Sort order is irrelevant for a GROUP BY clause. */
if( revSet ){
if( (rev ^ revIdx)!=pOrderBy->a[i].sortOrder ) return 0;
}else{
rev = revIdx ^ pOrderBy->a[i].sortOrder;
if( rev ) *pRevMask |= MASKBIT(iLoop);
revSet = 1;
}
}
}else{
/* No match found */
if( j==0 || j<nKeyCol ){
@@ -4912,8 +5021,14 @@ static int wherePathSatisfiesOrderBy(
}
}
} /* End the loop over all WhereLoops from outer-most down to inner-most */
if( obSat==obDone ) return 1;
if( !isOrderDistinct ) return 0;
if( obSat==obDone ) return (i8)nOrderBy;
if( !isOrderDistinct ){
for(i=nOrderBy-1; i>0; i--){
Bitmask m = MASKBIT(i) - 1;
if( (obSat&m)==m ) return i;
}
return 0;
}
return -1;
}
@@ -4950,11 +5065,11 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
int iLoop; /* Loop counter over the terms of the join */
int ii, jj; /* Loop counters */
int mxI = 0; /* Index of next entry to replace */
int nOrderBy; /* Number of ORDER BY clause terms */
LogEst rCost; /* Cost of a path */
LogEst nOut; /* Number of outputs */
LogEst mxCost = 0; /* Maximum cost of a set of paths */
LogEst mxOut = 0; /* Maximum nOut value on the set of paths */
LogEst rSortCost; /* Cost to do a sort */
int nTo, nFrom; /* Number of valid entries in aTo[] and aFrom[] */
WherePath *aFrom; /* All nFrom paths at the previous level */
WherePath *aTo; /* The nTo best paths at the current level */
@@ -4996,16 +5111,12 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Precompute the cost of sorting the final result set, if the caller
** to sqlite3WhereBegin() was concerned about sorting */
rSortCost = 0;
if( pWInfo->pOrderBy==0 || nRowEst==0 ){
aFrom[0].isOrderedValid = 1;
aFrom[0].isOrdered = 0;
nOrderBy = 0;
}else{
/* TUNING: Estimated cost of sorting is 48*N*log2(N) where N is the
** number of output rows. The 48 is the expected size of a row to sort.
** FIXME: compute a better estimate of the 48 multiplier based on the
** result set expressions. */
rSortCost = nRowEst + estLog(nRowEst);
WHERETRACE(0x002,("---- sort cost=%-3d\n", rSortCost));
aFrom[0].isOrdered = -1;
nOrderBy = pWInfo->pOrderBy->nExpr;
}
/* Compute successively longer WherePaths using the previous generation
@@ -5017,8 +5128,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){
Bitmask maskNew;
Bitmask revMask = 0;
u8 isOrderedValid = pFrom->isOrderedValid;
u8 isOrdered = pFrom->isOrdered;
i8 isOrdered = pFrom->isOrdered;
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
/* At this point, pWLoop is a candidate to be the next loop.
@@ -5027,21 +5137,35 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rCost = sqlite3LogEstAdd(rCost, pFrom->rCost);
nOut = pFrom->nRow + pWLoop->nOut;
maskNew = pFrom->maskLoop | pWLoop->maskSelf;
if( !isOrderedValid ){
switch( wherePathSatisfiesOrderBy(pWInfo,
if( isOrdered<0 ){
isOrdered = wherePathSatisfiesOrderBy(pWInfo,
pWInfo->pOrderBy, pFrom, pWInfo->wctrlFlags,
iLoop, pWLoop, &revMask) ){
case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */
isOrdered = 1;
isOrderedValid = 1;
break;
case 0: /* No. pFrom+pWLoop will require a separate sort */
isOrdered = 0;
isOrderedValid = 1;
rCost = sqlite3LogEstAdd(rCost, rSortCost);
break;
default: /* Cannot tell yet. Try again on the next iteration */
break;
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?
*/
LogEst rScale, rSortCost;
assert( nOrderBy>0 );
rScale = sqlite3LogEst((nOrderBy-isOrdered)*100/nOrderBy) - 66;
rSortCost = nRowEst + estLog(nRowEst) + rScale;
/* 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. */
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
rSortCost += 16;
}
WHERETRACE(0x002,
("---- sort cost=%-3d (%d/%d) increases cost %3d to %-3d\n",
rSortCost, (nOrderBy-isOrdered), nOrderBy, rCost,
sqlite3LogEstAdd(rCost,rSortCost)));
rCost = sqlite3LogEstAdd(rCost, rSortCost);
}
}else{
revMask = pFrom->revLoop;
@@ -5049,7 +5173,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
/* Check to see if pWLoop should be added to the mxChoice best so far */
for(jj=0, pTo=aTo; jj<nTo; jj++, pTo++){
if( pTo->maskLoop==maskNew
&& pTo->isOrderedValid==isOrderedValid
&& ((pTo->isOrdered^isOrdered)&80)==0
&& ((pTo->rCost<=rCost && pTo->nRow<=nOut) ||
(pTo->rCost>=rCost && pTo->nRow>=nOut))
){
@@ -5063,7 +5187,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("Skip %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
continue;
@@ -5081,7 +5205,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( sqlite3WhereTrace&0x4 ){
sqlite3DebugPrintf("New %s cost=%-3d,%3d order=%c\n",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
isOrdered>=0 ? isOrdered+'0' : '?');
}
#endif
}else{
@@ -5091,10 +5215,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
sqlite3DebugPrintf(
"Skip %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" vs %s cost=%-3d,%d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
testcase( pTo->rCost==rCost );
@@ -5107,10 +5231,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
sqlite3DebugPrintf(
"Update %s cost=%-3d,%3d order=%c",
wherePathName(pFrom, iLoop, pWLoop), rCost, nOut,
isOrderedValid ? (isOrdered ? 'Y' : 'N') : '?');
isOrdered>=0 ? isOrdered+'0' : '?');
sqlite3DebugPrintf(" was %s cost=%-3d,%3d order=%c\n",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
pTo->isOrdered>=0 ? pTo->isOrdered+'0' : '?');
}
#endif
}
@@ -5119,7 +5243,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
pTo->revLoop = revMask;
pTo->nRow = nOut;
pTo->rCost = rCost;
pTo->isOrderedValid = isOrderedValid;
pTo->isOrdered = isOrdered;
memcpy(pTo->aLoop, pFrom->aLoop, sizeof(WhereLoop*)*iLoop);
pTo->aLoop[iLoop] = pWLoop;
@@ -5144,8 +5267,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
for(ii=0, pTo=aTo; ii<nTo; ii++, pTo++){
sqlite3DebugPrintf(" %s cost=%-3d nrow=%-3d order=%c",
wherePathName(pTo, iLoop+1, 0), pTo->rCost, pTo->nRow,
pTo->isOrderedValid ? (pTo->isOrdered ? 'Y' : 'N') : '?');
if( pTo->isOrderedValid && pTo->isOrdered ){
pTo->isOrdered>=0 ? (pTo->isOrdered+'0') : '?');
if( pTo->isOrdered>0 ){
sqlite3DebugPrintf(" rev=0x%llx\n", pTo->revLoop);
}else{
sqlite3DebugPrintf("\n");
@@ -5188,13 +5311,18 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
Bitmask notUsed;
int rc = wherePathSatisfiesOrderBy(pWInfo, pWInfo->pResultSet, pFrom,
WHERE_DISTINCTBY, nLoop-1, pFrom->aLoop[nLoop-1], &notUsed);
if( rc==1 ) pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
if( pFrom->isOrdered ){
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
if( rc==pWInfo->pResultSet->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}
if( pWInfo->pOrderBy ){
if( pWInfo->wctrlFlags & WHERE_DISTINCTBY ){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
}else{
pWInfo->bOBSat = 1;
pWInfo->nOBSat = pFrom->isOrdered;
if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
pWInfo->revMask = pFrom->revLoop;
}
}
@@ -5279,7 +5407,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur);
pWInfo->a[0].iTabCur = iCur;
pWInfo->nRowOut = 1;
if( pWInfo->pOrderBy ) pWInfo->bOBSat = 1;
if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr;
if( pWInfo->wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
@@ -5383,7 +5511,7 @@ WhereInfo *sqlite3WhereBegin(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* FROM clause: A list of all tables to be scanned */
Expr *pWhere, /* The WHERE clause */
ExprList *pOrderBy, /* An ORDER BY clause, or NULL */
ExprList *pOrderBy, /* An ORDER BY (or GROUP BY) clause, or NULL */
ExprList *pResultSet, /* Result set of the query */
u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */
int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */
@@ -5405,6 +5533,10 @@ WhereInfo *sqlite3WhereBegin(
/* Variable initialization */
db = pParse->db;
memset(&sWLB, 0, sizeof(sWLB));
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
sWLB.pOrderBy = pOrderBy;
/* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via
@@ -5449,7 +5581,7 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
pWInfo->pResultSet = pResultSet;
pWInfo->iBreak = sqlite3VdbeMakeLabel(v);
pWInfo->iBreak = pWInfo->iContinue = sqlite3VdbeMakeLabel(v);
pWInfo->wctrlFlags = wctrlFlags;
pWInfo->savedNQueryLoop = pParse->nQueryLoop;
pMaskSet = &pWInfo->sMaskSet;
@@ -5483,7 +5615,7 @@ WhereInfo *sqlite3WhereBegin(
/* Special case: No FROM clause
*/
if( nTabList==0 ){
if( pOrderBy ) pWInfo->bOBSat = 1;
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
@@ -5594,8 +5726,8 @@ WhereInfo *sqlite3WhereBegin(
if( sqlite3WhereTrace ){
int ii;
sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut);
if( pWInfo->bOBSat ){
sqlite3DebugPrintf(" ORDERBY=0x%llx", pWInfo->revMask);
if( pWInfo->nOBSat>0 ){
sqlite3DebugPrintf(" ORDERBY=%d,0x%llx", pWInfo->nOBSat, pWInfo->revMask);
}
switch( pWInfo->eDistinct ){
case WHERE_DISTINCT_UNIQUE: {
@@ -5877,7 +6009,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
for(; k<last; k++, pOp++){
if( pOp->p1!=pLevel->iTabCur ) continue;
if( pOp->opcode==OP_Column ){
pOp->opcode = OP_SCopy;
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + pTabItem->regResult;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
+3 -4
View File
@@ -121,7 +121,7 @@ struct WhereLoop {
struct { /* Information for virtual tables */
int idxNum; /* Index number */
u8 needFree; /* True if sqlite3_free(idxStr) is needed */
u8 isOrdered; /* True if satisfies ORDER BY */
i8 isOrdered; /* True if satisfies ORDER BY */
u16 omitMask; /* Terms that may be omitted */
char *idxStr; /* Index identifier string */
} vtab;
@@ -183,8 +183,7 @@ struct WherePath {
Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */
LogEst nRow; /* Estimated number of rows generated by this path */
LogEst rCost; /* Total cost of this path */
u8 isOrdered; /* True if this path satisfies ORDER BY */
u8 isOrderedValid; /* True if the isOrdered field is valid */
i8 isOrdered; /* No. of ORDER BY terms satisfied. -1 for unknown */
WhereLoop **aLoop; /* Array of WhereLoop objects implementing this path */
};
@@ -398,7 +397,7 @@ struct WhereInfo {
Bitmask revMask; /* Mask of ORDER BY terms that need reversing */
LogEst nRowOut; /* Estimated number of output rows */
u16 wctrlFlags; /* Flags originally passed to sqlite3WhereBegin() */
u8 bOBSat; /* ORDER BY satisfied by indices */
i8 nOBSat; /* Number of ORDER BY terms satisfied by indices */
u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */
u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */
u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */
+3 -8
View File
@@ -47,12 +47,12 @@ do_test 1.2 {
catchsql {
SELECT c FROM t1 WHERE a>'abc';
}
} {0 {}}
} {1 {database disk image is malformed}}
do_test 1.3 {
catchsql {
PRAGMA integrity_check
}
} {0 ok}
} {1 {database disk image is malformed}}
do_test 1.4 {
catchsql {
SELECT c FROM t1 ORDER BY a;
@@ -71,11 +71,6 @@ do_test 2.1 {
catchsql {
SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ';
}
# The following test result is brittle. The point above is to try to
# force a buffer overread by a corrupt database file. If we get an
# incorrect answer from a corrupt database file, that is OK. If the
# result below changes, that just means that "undefined behavior" has
# changed.
} {/0 .*/}
} {1 {database disk image is malformed}}
finish_test
+32 -5
View File
@@ -32,21 +32,48 @@ do_execsql_test 1.1 {
PRAGMA auto_vacuum=0;
CREATE TABLE t1(a);
CREATE INDEX i1 ON t1(a);
INSERT INTO t1 VALUES('a');
INSERT INTO t1 VALUES('abcdefghijklmnop');
} {}
db close
do_test 1.2 {
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
set off [expr 2*1024 + $offset + 1]
hexio_write test.db $off FF06
breakpoint
hexio_write test.db $off 7f06
sqlite3 db test.db
catchsql { SELECT * FROM t1 WHERE a = 10 }
} {0 {}}
do_test 1.3 {
db close
set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]]
set off [expr 2*1024 + $offset + 1]
hexio_write test.db $off FFFF7f02
sqlite3 db test.db
catchsql { SELECT * FROM t1 WHERE a = 10 }
} {1 {database disk image is malformed}}
do_test 2.0 {
execsql {
CREATE TABLE r(x);
INSERT INTO r VALUES('ABCDEFGHIJK');
CREATE INDEX r1 ON r(x);
}
set pg [db one {SELECT rootpage FROM sqlite_master WHERE name = 'r1'}]
} {5}
do_test 2.1 {
db close
set offset [hexio_get_int [hexio_read test.db [expr (5-1)*1024 + 8] 2]]
set off [expr (5-1)*1024 + $offset + 1]
hexio_write test.db $off FFFF0004
sqlite3 db test.db
catchsql { SELECT * FROM r WHERE x >= 10.0 }
} {1 {database disk image is malformed}}
do_test 2.2 {
catchsql { SELECT * FROM r WHERE x >= 10 }
} {1 {database disk image is malformed}}
finish_test
+1 -1
View File
@@ -162,7 +162,7 @@ do_execsql_test 2.0 {
foreach {tn sql temptables res} {
1 "a, b FROM t1" {} {A B a b}
2 "b, a FROM t1" {} {B A b a}
3 "a, b, c FROM t1" {hash} {a b c A B C}
3 "a, b, c FROM t1" {hash} {A B C a b c}
4 "a, b, c FROM t1 ORDER BY a, b, c" {btree} {A B C a b c}
5 "b FROM t1 WHERE a = 'a'" {} {b}
6 "b FROM t1 ORDER BY +b COLLATE binary" {btree hash} {B b}
+28
View File
@@ -219,4 +219,32 @@ do_execsql_test 5.2 {
SELECT count(*) FROM sqlite_master WHERE name LIKE 't8%';
} {0 6}
# At one point this was causing a memory leak.
#
foreach {tn sql} {
1 {}
2 { INSERT INTO ft(ft) VALUES('merge=2,2'); }
} {
reset_db
do_execsql_test 6.$tn.1 "
CREATE TABLE t1(x);
CREATE VIRTUAL TABLE ft USING fts3;
INSERT INTO ft VALUES('hello world');
$sql
"
db close
sqlite3 db test.db
do_execsql_test 6.$tn.2 { SELECT * FROM t1 } {}
do_test 6.$tn.3 {
sqlite3 db2 test.db
db2 eval { DROP TABLE t1 }
db2 close
set stmt [sqlite3_prepare db { SELECT * FROM ft } -1 dummy]
sqlite3_finalize $stmt
} {SQLITE_OK}
db close
}
finish_test
+11
View File
@@ -354,6 +354,17 @@ do_test fts3d-6.5 {
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
}
} {xyz_content xyz_segdir xyz_segments}
# ALTER TABLE RENAME on an FTS3 table following an incr-merge op.
#
do_test fts3d-6.6 {
execsql { INSERT INTO xyz(xyz) VALUES('merge=2,2') }
sqlite3 db test.db
execsql {
ALTER TABLE xyz RENAME TO ott;
SELECT name FROM sqlite_master WHERE name GLOB '???_*' ORDER BY 1;
}
} {ott_content ott_segdir ott_segments ott_stat}
finish_test
+177
View File
@@ -159,4 +159,181 @@ do_test in4-3.12 {
execsql { SELECT * FROM t3 WHERE x IN (1, 2) AND y IN ()}
} {}
# Tests for "... IN (?)" and "... NOT IN (?)". In other words, tests
# for when the RHS of IN is a single expression. This should work the
# same as the == and <> operators.
#
do_execsql_test in4-3.21 {
SELECT * FROM t3 WHERE x=10 AND y IN (10);
} {10 10 10}
do_execsql_test in4-3.22 {
SELECT * FROM t3 WHERE x IN (10) AND y=10;
} {10 10 10}
do_execsql_test in4-3.23 {
SELECT * FROM t3 WHERE x IN (10) AND y IN (10);
} {10 10 10}
do_execsql_test in4-3.24 {
SELECT * FROM t3 WHERE x=1 AND y NOT IN (10);
} {1 1 1}
do_execsql_test in4-3.25 {
SELECT * FROM t3 WHERE x NOT IN (10) AND y=1;
} {1 1 1}
do_execsql_test in4-3.26 {
SELECT * FROM t3 WHERE x NOT IN (10) AND y NOT IN (10);
} {1 1 1}
# The query planner recognizes that "x IN (?)" only generates a
# single match and can use this information to optimize-out ORDER BY
# clauses.
#
do_execsql_test in4-3.31 {
DROP INDEX t3i1;
CREATE UNIQUE INDEX t3xy ON t3(x,y);
SELECT *, '|' FROM t3 A, t3 B
WHERE A.x=10 AND A.y IN (10)
AND B.x=1 AND B.y IN (1);
} {10 10 10 1 1 1 |}
do_execsql_test in4-3.32 {
EXPLAIN QUERY PLAN
SELECT *, '|' FROM t3 A, t3 B
WHERE A.x=10 AND A.y IN (10)
AND B.x=1 AND B.y IN (1);
} {~/B-TREE/} ;# No separate sorting pass
do_execsql_test in4-3.33 {
SELECT *, '|' FROM t3 A, t3 B
WHERE A.x IN (10) AND A.y=10
AND B.x IN (1) AND B.y=1;
} {10 10 10 1 1 1 |}
do_execsql_test in4-3.34 {
EXPLAIN QUERY PLAN
SELECT *, '|' FROM t3 A, t3 B
WHERE A.x IN (10) AND A.y=10
AND B.x IN (1) AND B.y=1;
} {~/B-TREE/} ;# No separate sorting pass
# An expression of the form "x IN (?,?)" creates an ephemeral table to
# hold the list of values on the RHS. But "x IN (?)" does not create
# an ephemeral table.
#
do_execsql_test in4-3.41 {
SELECT * FROM t3 WHERE x IN (10,11);
} {10 10 10}
do_execsql_test in4-3.42 {
EXPLAIN
SELECT * FROM t3 WHERE x IN (10,11);
} {/OpenEphemeral/}
do_execsql_test in4-3.43 {
SELECT * FROM t3 WHERE x IN (10);
} {10 10 10}
do_execsql_test in4-3.44 {
EXPLAIN
SELECT * FROM t3 WHERE x IN (10);
} {~/OpenEphemeral/}
do_execsql_test in4-3.45 {
SELECT * FROM t3 WHERE x NOT IN (10,11);
} {1 1 1}
do_execsql_test in4-3.46 {
EXPLAIN
SELECT * FROM t3 WHERE x NOT IN (10,11);
} {/OpenEphemeral/}
do_execsql_test in4-3.47 {
SELECT * FROM t3 WHERE x NOT IN (10);
} {1 1 1}
do_execsql_test in4-3.48 {
EXPLAIN
SELECT * FROM t3 WHERE x NOT IN (10);
} {~/OpenEphemeral/}
# Make sure that when "x IN (?)" is converted into "x==?" that collating
# sequence and affinity computations do not get messed up.
#
do_execsql_test in4-4.1 {
CREATE TABLE t4a(a TEXT, b TEXT COLLATE nocase, c);
INSERT INTO t4a VALUES('ABC','abc',1);
INSERT INTO t4a VALUES('def','xyz',2);
INSERT INTO t4a VALUES('ghi','ghi',3);
SELECT c FROM t4a WHERE a=b ORDER BY c;
} {3}
do_execsql_test in4-4.2 {
SELECT c FROM t4a WHERE b=a ORDER BY c;
} {1 3}
do_execsql_test in4-4.3 {
SELECT c FROM t4a WHERE (a||'')=b ORDER BY c;
} {1 3}
do_execsql_test in4-4.4 {
SELECT c FROM t4a WHERE (a||'')=(b||'') ORDER BY c;
} {3}
do_execsql_test in4-4.5 {
SELECT c FROM t4a WHERE a IN (b) ORDER BY c;
} {3}
do_execsql_test in4-4.6 {
SELECT c FROM t4a WHERE (a||'') IN (b) ORDER BY c;
} {3}
do_execsql_test in4-4.11 {
CREATE TABLE t4b(a TEXT, b NUMERIC, c);
INSERT INTO t4b VALUES('1.0',1,4);
SELECT c FROM t4b WHERE a=b;
} {4}
do_execsql_test in4-4.12 {
SELECT c FROM t4b WHERE b=a;
} {4}
do_execsql_test in4-4.13 {
SELECT c FROM t4b WHERE +a=b;
} {4}
do_execsql_test in4-4.14 {
SELECT c FROM t4b WHERE a=+b;
} {}
do_execsql_test in4-4.15 {
SELECT c FROM t4b WHERE +b=a;
} {}
do_execsql_test in4-4.16 {
SELECT c FROM t4b WHERE b=+a;
} {4}
do_execsql_test in4-4.17 {
SELECT c FROM t4b WHERE a IN (b);
} {}
do_execsql_test in4-4.18 {
SELECT c FROM t4b WHERE b IN (a);
} {4}
do_execsql_test in4-4.19 {
SELECT c FROM t4b WHERE +b IN (a);
} {}
do_execsql_test in4-5.1 {
CREATE TABLE t5(c INTEGER PRIMARY KEY, d TEXT COLLATE nocase);
INSERT INTO t5 VALUES(17, 'fuzz');
SELECT 1 FROM t5 WHERE 'fuzz' IN (d); -- match
SELECT 2 FROM t5 WHERE 'FUZZ' IN (d); -- no match
SELECT 3 FROM t5 WHERE d IN ('fuzz'); -- match
SELECT 4 FROM t5 WHERE d IN ('FUZZ'); -- match
} {1 3 4}
# An expression of the form "x IN (y)" can be used as "x=y" by the
# query planner when computing transitive constraints or to run the
# query using an index on y.
#
do_execsql_test in4-6.1 {
CREATE TABLE t6a(a INTEGER PRIMARY KEY, b);
INSERT INTO t6a VALUES(1,2),(3,4),(5,6);
CREATE TABLE t6b(c INTEGER PRIMARY KEY, d);
INSERT INTO t6b VALUES(4,44),(5,55),(6,66);
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
} {3 4 4 44}
do_execsql_test in4-6.1-eqp {
EXPLAIN QUERY PLAN
SELECT * FROM t6a, t6b WHERE a=3 AND b IN (c);
} {~/SCAN/}
do_execsql_test in4-6.2 {
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
} {3 4 4 44}
do_execsql_test in4-6.2-eqp {
EXPLAIN QUERY PLAN
SELECT * FROM t6a, t6b WHERE a=3 AND c IN (b);
} {~/SCAN/}
finish_test
+20
View File
@@ -616,4 +616,24 @@ do_test limit-13.81 {
db eval {SELECT z FROM v13c LIMIT 1 OFFSET 8}
} {}
do_execsql_test limit-14.1 {
SELECT 123 LIMIT 1 OFFSET 0
} {123}
do_execsql_test limit-14.2 {
SELECT 123 LIMIT 1 OFFSET 1
} {}
do_execsql_test limit-14.3 {
SELECT 123 LIMIT 0 OFFSET 0
} {}
do_execsql_test limit-14.4 {
SELECT 123 LIMIT 0 OFFSET 1
} {}
do_execsql_test limit-14.6 {
SELECT 123 LIMIT -1 OFFSET 0
} {123}
do_execsql_test limit-14.7 {
SELECT 123 LIMIT -1 OFFSET 1
} {}
finish_test
+22
View File
@@ -880,6 +880,28 @@ 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
}
# 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}
+20 -2
View File
@@ -64,10 +64,28 @@ do_execsql_test 1.7 {
EXPLAIN QUERY PLAN
SELECT DISTINCT c, b, a FROM t1 WHERE +a=0;
} {/B-TREE/}
do_execsql_test 2.1 {
# In some cases, it is faster to do repeated index lookups than it is to
# sort. But in other cases, it is faster to sort than to do repeated index
# lookups.
#
do_execsql_test 2.1a {
CREATE TABLE t2(a,b,c);
CREATE INDEX t2bc ON t2(b,c);
ANALYZE;
INSERT INTO sqlite_stat1 VALUES('t1','t1bc','1000000 10 9');
INSERT INTO sqlite_stat1 VALUES('t2','t2bc','100 10 5');
ANALYZE sqlite_master;
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;
} {~/B-TREE/}
} {/B-TREE/}
do_execsql_test 2.2 {
EXPLAIN QUERY PLAN
SELECT * FROM t1 WHERE +a=0 ORDER BY a, b, c;
+183
View File
@@ -0,0 +1,183 @@
# 2014-03-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 implements regression tests for SQLite library. The
# focus of this file is testing that the block-sort optimization.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix orderby6
# Run all tests twice. Once with a normal table and a second time
# with a WITHOUT ROWID table
#
foreach {tn rowidclause} {1 {} 2 {WITHOUT ROWID}} {
# Construct a table with 1000 rows and a split primary key
#
reset_db
do_test $tn.1 {
db eval "CREATE TABLE t1(a,b,c,PRIMARY KEY(b,c)) $rowidclause;"
db eval {
WITH RECURSIVE
cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<1000)
INSERT INTO t1 SELECT x, x%40, x/40 FROM cnt;
}
} {}
# Run various ORDER BY queries that can benefit from block-sort.
# Compare the output to the same output using a full-sort enforced
# by adding + to each term of the ORDER BY clause.
#
do_execsql_test $tn.2 {
SELECT b,a,c FROM t1 ORDER BY b,a,c;
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+a,+c}]
do_execsql_test $tn.3 {
SELECT b,a,c FROM t1 ORDER BY b,c DESC,a;
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b,+c DESC,+a}]
do_execsql_test $tn.4 {
SELECT b,a,c FROM t1 ORDER BY b DESC,c,a;
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+c,+a}]
do_execsql_test $tn.5 {
SELECT b,a,c FROM t1 ORDER BY b DESC,a,c;
} [db eval {SELECT b,a,c FROM t1 ORDER BY +b DESC,+a,+c}]
# LIMIT and OFFSET clauses on block-sort queries.
#
do_execsql_test $tn.11 {
SELECT a FROM t1 ORDER BY b, a LIMIT 10 OFFSET 20;
} {840 880 920 960 1000 1 41 81 121 161}
do_execsql_test $tn.11x {
SELECT a FROM t1 ORDER BY +b, a LIMIT 10 OFFSET 20;
} {840 880 920 960 1000 1 41 81 121 161}
do_execsql_test $tn.12 {
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 20;
} {839 879 919 959 999 38 78 118 158 198}
do_execsql_test $tn.12 {
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 20;
} {839 879 919 959 999 38 78 118 158 198}
do_execsql_test $tn.13 {
SELECT a FROM t1 ORDER BY b, a DESC LIMIT 10 OFFSET 45;
} {161 121 81 41 1 962 922 882 842 802}
do_execsql_test $tn.13x {
SELECT a FROM t1 ORDER BY +b, a DESC LIMIT 10 OFFSET 45;
} {161 121 81 41 1 962 922 882 842 802}
do_execsql_test $tn.14 {
SELECT a FROM t1 ORDER BY b DESC, a LIMIT 10 OFFSET 45;
} {838 878 918 958 998 37 77 117 157 197}
do_execsql_test $tn.14x {
SELECT a FROM t1 ORDER BY +b DESC, a LIMIT 10 OFFSET 45;
} {838 878 918 958 998 37 77 117 157 197}
# Many test cases where the LIMIT+OFFSET window is in various
# alignments with block-sort boundaries.
#
foreach {tx limit offset orderby} {
1 10 24 {+b,+a}
2 10 25 {+b,+a}
3 10 26 {+b,+a}
4 10 39 {+b,+a}
5 10 40 {+b,+a}
6 10 41 {+b,+a}
7 27 24 {+b,+a}
8 27 49 {+b,+a}
11 10 24 {+b DESC,+a}
12 10 25 {+b DESC,+a}
13 10 26 {+b DESC,+a}
14 10 39 {+b DESC,+a}
15 10 40 {+b DESC,+a}
16 10 41 {+b DESC,+a}
17 27 24 {+b DESC,+a}
18 27 49 {+b DESC,+a}
21 10 24 {+b,+a DESC}
22 10 25 {+b,+a DESC}
23 10 26 {+b,+a DESC}
24 10 39 {+b,+a DESC}
25 10 40 {+b,+a DESC}
26 10 41 {+b,+a DESC}
27 27 24 {+b,+a DESC}
28 27 49 {+b,+a DESC}
31 10 24 {+b DESC,+a DESC}
32 10 25 {+b DESC,+a DESC}
33 10 26 {+b DESC,+a DESC}
34 10 39 {+b DESC,+a DESC}
35 10 40 {+b DESC,+a DESC}
36 10 41 {+b DESC,+a DESC}
37 27 24 {+b DESC,+a DESC}
38 27 49 {+b DESC,+a DESC}
} {
set sql1 "SELECT a FROM t1 ORDER BY $orderby LIMIT $limit OFFSET $offset;"
set sql2 [string map {+ {}} $sql1]
# puts $sql2\n$sql1\n[db eval $sql2]
do_test $tn.21.$tx {db eval $::sql2} [db eval $sql1]
}
########################################################################
# A second test table, t2, has many columns open to sorting.
do_test $tn.31 {
db eval "CREATE TABLE t2(a,b,c,d,e,f,PRIMARY KEY(b,c,d,e,f)) $rowidclause;"
db eval {
WITH RECURSIVE
cnt(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM cnt WHERE x<242)
INSERT INTO t2 SELECT x, x%3, (x/3)%3, (x/9)%3, (x/27)%3, (x/81)%3
FROM cnt;
}
} {}
do_execsql_test $tn.32 {
SELECT a FROM t2 ORDER BY b,c,d,e,f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
do_execsql_test $tn.33 {
SELECT a FROM t2 ORDER BY b,c,d,e,+f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
do_execsql_test $tn.34 {
SELECT a FROM t2 ORDER BY b,c,d,+e,+f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
do_execsql_test $tn.35 {
SELECT a FROM t2 ORDER BY b,c,+d,+e,+f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
do_execsql_test $tn.36 {
SELECT a FROM t2 ORDER BY b,+c,+d,+e,+f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f;}]
do_execsql_test $tn.37 {
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC;}]
do_execsql_test $tn.38 {
SELECT a FROM t2 ORDER BY b,c,d,e DESC,f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e DESC,+f;}]
do_execsql_test $tn.39 {
SELECT a FROM t2 ORDER BY b,c,d DESC,e,f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d DESC,+e,+f;}]
do_execsql_test $tn.40 {
SELECT a FROM t2 ORDER BY b,c DESC,d,e,f;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c DESC,+d,+e,+f;}]
do_execsql_test $tn.41 {
SELECT a FROM t2 ORDER BY b DESC,c,d,e,f;
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c,+d,+e,+f;}]
do_execsql_test $tn.42 {
SELECT a FROM t2 ORDER BY b DESC,c DESC,d,e,f LIMIT 31;
} [db eval {SELECT a FROM t2 ORDER BY +b DESC,+c DESC,+d,+e,+f LIMIT 31}]
do_execsql_test $tn.43 {
SELECT a FROM t2 ORDER BY b,c,d,e,f DESC LIMIT 8 OFFSET 7;
} [db eval {SELECT a FROM t2 ORDER BY +b,+c,+d,+e,+f DESC LIMIT 8 OFFSET 7}]
}
finish_test
+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
}]
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
+38
View File
@@ -209,4 +209,42 @@ do_execsql_test skipscan1-4.1 {
SELECT i FROM t4 WHERE h=8;
} {9 9 9 9 9 9 9 9}
# Make sure skip-scan cost computation in the query planner takes into
# account the fact that the seek must occur multiple times.
#
# Prior to 2014-03-10, the costs were computed incorrectly which would
# cause index t5i2 to be used instead of t5i1 on the skipscan1-5.3.
#
do_execsql_test skipscan1-5.1 {
CREATE TABLE t5(
id INTEGER PRIMARY KEY,
loc TEXT,
lang INTEGER,
utype INTEGER,
xa INTEGER,
xd INTEGER,
xh INTEGER
);
CREATE INDEX t5i1 on t5(loc, xh, xa, utype, lang);
CREATE INDEX t5i2 ON t5(xd,loc,utype,lang);
EXPLAIN QUERY PLAN
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
} {/.*COVERING INDEX t5i1 .*/}
do_execsql_test skipscan1-5.2 {
ANALYZE;
DELETE FROM sqlite_stat1;
DROP TABLE IF EXISTS sqlite_stat4;
DROP TABLE IF EXISTS sqlite_stat3;
INSERT INTO sqlite_stat1 VALUES('t5','t5i1','2702931 3 2 2 2 2');
INSERT INTO sqlite_stat1 VALUES('t5','t5i2','2702931 686 2 2 2');
ANALYZE sqlite_master;
} {}
db cache flush
do_execsql_test skipscan1-5.3 {
EXPLAIN QUERY PLAN
SELECT xh, loc FROM t5 WHERE loc >= 'M' AND loc < 'N';
} {/.*COVERING INDEX t5i1 .*/}
finish_test
+22
View File
@@ -464,4 +464,26 @@ 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}]
finish_test
+55
View File
@@ -0,0 +1,55 @@
# 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.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix sort2
db close
sqlite3_shutdown
sqlite3_config_worker_threads 7
reset_db
do_execsql_test 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 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 2.2 {
CREATE UNIQUE INDEX i1 ON t1(b, a);
}
db close
sqlite3_shutdown
sqlite3_config_worker_threads 0
sqlite3_initialize
finish_test
+63
View File
@@ -0,0 +1,63 @@
# 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.
#
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
+41 -2
View File
@@ -474,7 +474,7 @@ void testset_main(void){
speedtest1_end_test();
n = g.szTest/2;
n = 25;
speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n);
speedtest1_exec("BEGIN");
speedtest1_prepare(
@@ -492,7 +492,7 @@ void testset_main(void){
speedtest1_end_test();
n = g.szTest/5;
n = 10;
speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n);
speedtest1_exec("BEGIN");
speedtest1_prepare(
@@ -512,6 +512,45 @@ void testset_main(void){
speedtest1_end_test();
n = 10;
speedtest1_begin_test(142, "%d SELECTS w/ORDER BY, unindexed", n);
speedtest1_exec("BEGIN");
speedtest1_prepare(
"SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
" ORDER BY a; -- %d times", n
);
for(i=1; i<=n; i++){
x1 = speedtest1_random()%maxb;
zNum[0] = '%';
len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
zNum[len] = '%';
zNum[len+1] = 0;
sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
speedtest1_run();
}
speedtest1_exec("COMMIT");
speedtest1_end_test();
n = 10; //g.szTest/5;
speedtest1_begin_test(145, "%d SELECTS w/ORDER BY and LIMIT, unindexed", n);
speedtest1_exec("BEGIN");
speedtest1_prepare(
"SELECT a, b, c FROM t1 WHERE c LIKE ?1\n"
" ORDER BY a LIMIT 10; -- %d times", n
);
for(i=1; i<=n; i++){
x1 = speedtest1_random()%maxb;
zNum[0] = '%';
len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
zNum[len] = '%';
zNum[len+1] = 0;
sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
speedtest1_run();
}
speedtest1_exec("COMMIT");
speedtest1_end_test();
speedtest1_begin_test(150, "CREATE INDEX five times");
speedtest1_exec("BEGIN;");
speedtest1_exec("CREATE UNIQUE INDEX t1b ON t1(b);");
+1
View File
@@ -61,6 +61,7 @@ foreach s {
fcntl read pread write pwrite fchmod fallocate
pread64 pwrite64 unlink openDirectory mkdir rmdir
statvfs fchown umask mmap munmap mremap
getpagesize
} {
if {[test_syscall exists $s]} {lappend syscall_list $s}
}
+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
+93
View File
@@ -0,0 +1,93 @@
# 2014-03-24
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests to verify that arithmetic operators do not change the type of
# input operands. Ticket [a8a0d2996a]
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-a8a0d2996a
do_execsql_test 1.0 {
CREATE TABLE t(x,y);
INSERT INTO t VALUES('1','1');
SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1';
} {text text}
do_execsql_test 1.1 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1';
} {text text}
do_execsql_test 1.2 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1';
} {text text}
do_execsql_test 1.3 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1';
} {text text}
do_execsql_test 1.4 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1';
} {text text}
do_execsql_test 2.0 {
UPDATE t SET x='1xyzzy';
SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1';
} {text text}
do_execsql_test 2.1 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1';
} {text text}
do_execsql_test 2.2 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1';
} {text text}
do_execsql_test 2.3 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1';
} {text text}
do_execsql_test 2.4 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1';
} {text text}
do_execsql_test 3.0 {
UPDATE t SET x='1.0';
SELECT typeof(x), typeof(y) FROM t WHERE 1=x+0 AND y=='1';
} {text text}
do_execsql_test 3.1 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x-0 AND y=='1';
} {text text}
do_execsql_test 3.2 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x*1 AND y=='1';
} {text text}
do_execsql_test 3.3 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x/1 AND y=='1';
} {text text}
do_execsql_test 3.4 {
SELECT typeof(x), typeof(y) FROM t WHERE 1=x%4 AND y=='1';
} {text text}
do_execsql_test 4.0 {
SELECT 1+1.;
} {2.0}
do_execsql_test 4.1 {
SELECT '1.23e64'/'1.0000e+62';
} {123.0}
do_execsql_test 4.2 {
SELECT '100x'+'-2y';
} {98}
do_execsql_test 4.3 {
SELECT '100x'+'4.5y';
} {104.5}
do_execsql_test 4.4 {
SELECT '-9223372036854775807x'-'1x';
} {-9.22337203685478e+18}
do_execsql_test 4.5 {
SELECT '9223372036854775806x'+'1x';
} {9.22337203685478e+18}
do_execsql_test 4.6 {
SELECT '1234x'/'10y';
} {123.4}
+47
View File
@@ -15,6 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix vtab_shared
ifcapable !vtab||!shared_cache {
finish_test
@@ -228,5 +229,51 @@ do_test vtab_shared_1.15.3 {
db close
db2 close
#---------------------------------------------------------------
# Test calling sqlite3_close() with vtabs on the disconnect list.
#
ifcapable rtree {
reset_db
do_test 2.1.1 {
sqlite3 db test.db
sqlite3 db2 test.db
# Create a virtual table using [db].
execsql {
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
INSERT INTO rt VALUES(1, 2 ,3);
SELECT * FROM rt;
}
# Drop the virtual table using [db2]. The sqlite3_vtab object belonging
# to [db] is moved to the sqlite3.pDisconnect list.
execsql { DROP TABLE rt } db2
# Immediately close [db]. At one point this would fail due to the
# unfinalized statements held by the un-xDisconnect()ed sqlite3_vtab.
db close
} {}
db2 close
}
ifcapable fts3 {
# Same test as above, except using fts3 instead of rtree.
reset_db
do_test 2.2.1 {
sqlite3 db test.db
sqlite3 db2 test.db
execsql {
CREATE VIRTUAL TABLE ft USING fts3;
INSERT INTO ft VALUES('hello world');
SELECT * FROM ft;
}
execsql { DROP TABLE ft } db2
db close
} {}
db2 close
}
sqlite3_enable_shared_cache 0
finish_test
+13
View File
@@ -1574,4 +1574,17 @@ sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
# Make sure PRAGMA journal_mode=WAL works with ATTACHED databases in
# all journal modes.
#
foreach mode {OFF MEMORY PERSIST DELETE TRUNCATE WAL} {
delete_file test.db test2.db
sqlite3 db test.db
do_test wal-25.$mode {
db eval "PRAGMA journal_mode=$mode"
db eval {ATTACH 'test2.db' AS t2; PRAGMA journal_mode=WAL;}
} {wal}
db close
}
finish_test
+51
View File
@@ -0,0 +1,51 @@
# 2010 April 13
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing the operation of the library in
# "PRAGMA journal_mode=WAL" mode.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix wal64k
ifcapable !wal {finish_test ; return }
if {$tcl_platform(platform) != "unix"} {
finish_test
return
}
db close
test_syscall pagesize 65536
sqlite3 db test.db
do_execsql_test 1.0 {
PRAGMA journal_mode = WAL;
CREATE TABLE t1(x);
CREATE INDEX i1 ON t1(x);
} {wal}
do_test 1.1 { file size test.db-shm } {65536}
do_test 1.2 {
execsql BEGIN
while {[file size test.db-shm]==65536} {
execsql { INSERT INTO t1 VALUES( randstr(900,1100) ) }
}
execsql COMMIT
file size test.db-shm
} {131072}
integrity_check 1.3
db close
test_syscall pagesize -1
finish_test
+15 -2
View File
@@ -95,7 +95,7 @@ do_eqp_test whereG-1.5 {
WHERE cname LIKE '%bach%'
AND composer.cid=track.cid
AND album.aid=track.aid;
} {/.*track.*composer.*album.*/}
} {/.*track.*(composer.*album|album.*composer).*/}
do_execsql_test whereG-1.6 {
SELECT DISTINCT aname
FROM album, composer, track
@@ -110,7 +110,7 @@ do_eqp_test whereG-1.7 {
WHERE cname LIKE '%bach%'
AND unlikely(composer.cid=track.cid)
AND unlikely(album.aid=track.aid);
} {/.*track.*composer.*album.*/}
} {/.*track.*(composer.*album|album.*composer).*/}
do_execsql_test whereG-1.8 {
SELECT DISTINCT aname
FROM album, composer, track
@@ -166,5 +166,18 @@ do_eqp_test whereG-3.4 {
SELECT * FROM a, b WHERE a2=5 AND a1=b1;
} {/.*SCAN TABLE a.*SEARCH TABLE b USING INDEX .*b_1 .b1=..*/}
# Ticket [1e64dd782a126f48d78c43a664844a41d0e6334e]:
# Incorrect result in a nested GROUP BY/DISTINCT due to the use of an OP_SCopy
# where an OP_Copy was needed.
#
do_execsql_test whereG-4.0 {
CREATE TABLE t4(x);
INSERT INTO t4 VALUES('right'),('wrong');
SELECT DISTINCT x
FROM (SELECT x FROM t4 GROUP BY x)
WHERE x='right'
ORDER BY x;
} {right}
finish_test
+139
View File
@@ -0,0 +1,139 @@
# 2014-03-31
#
# 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 cases for query planning decisions where one candidate index
# covers a proper superset of the WHERE clause terms of another
# candidate index.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test whereH-1.1 {
CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1abc ON t1(a,b,c);
CREATE INDEX t1bc ON t1(b,c);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {/INDEX t1abc /}
do_execsql_test whereH-1.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-2.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1bc ON t1(b,c);
CREATE INDEX t1abc ON t1(a,b,c);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {/INDEX t1abc /}
do_execsql_test whereH-2.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c>=? ORDER BY c;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-3.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-3.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-4.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-4.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-5.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-5.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-6.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1cd ON t1(c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-6.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-7.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
CREATE INDEX t1cd ON t1(c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-7.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
do_execsql_test whereH-8.1 {
DROP TABLE t1;
CREATE TABLE t1(a,b,c,d,e);
CREATE INDEX t1abcd ON t1(a,b,c,d);
CREATE INDEX t1cd ON t1(c,d);
CREATE INDEX t1bcd ON t1(b,c,d);
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {/INDEX t1abcd /}
do_execsql_test whereH-8.2 {
EXPLAIN QUERY PLAN
SELECT d FROM t1 WHERE a=? AND b=? AND c=? AND d>=? ORDER BY d;
} {~/TEMP B-TREE FOR ORDER BY/}
finish_test
+27
View File
@@ -385,6 +385,33 @@ do_execsql_test 7.5 {
)
} {14 28 42}
#-------------------------------------------------------------------------
# At one point the following was causing an assertion failure and a
# memory leak.
#
do_execsql_test 8.1 {
CREATE TABLE t7(y);
INSERT INTO t7 VALUES(NULL);
CREATE VIEW v AS SELECT * FROM t7 ORDER BY y;
}
do_execsql_test 8.2 {
WITH q(a) AS (
SELECT 1
UNION
SELECT a+1 FROM q, v WHERE a<5
)
SELECT * FROM q;
} {1 2 3 4 5}
do_execsql_test 8.3 {
WITH q(a) AS (
SELECT 1
UNION ALL
SELECT a+1 FROM q, v WHERE a<5
)
SELECT * FROM q;
} {1 2 3 4 5}
finish_test
+44 -18
View File
@@ -17,13 +17,7 @@
**
** ./LogEst ARGS
**
** Arguments:
**
** 'x' Multiple the top two elements of the stack
** '+' Add the top two elements of the stack
** NUM Convert NUM from integer to LogEst and push onto the stack
** ^NUM Interpret NUM as a LogEst and push onto stack.
**
** See the showHelp() routine for a description of valid arguments.
** Examples:
**
** To convert 123 from LogEst to integer:
@@ -97,12 +91,31 @@ static LogEst logEstFromDouble(double x){
return e*10;
}
int isInteger(const char *z){
while( z[0]>='0' && z[0]<='9' ) z++;
return z[0]==0;
}
int isFloat(const char *z){
while( z[0] ){
if( z[0]=='.' || z[0]=='E' || z[0]=='e' ) return 1;
z++;
}
return 0;
char c;
while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e'
|| c=='+' || c=='-' ) z++;
return z[0]==0;
}
static void showHelp(const char *zArgv0){
printf("Usage: %s ARGS...\n", zArgv0);
printf("Arguments:\n"
" NUM Convert NUM from integer to LogEst and push onto the stack\n"
" ^NUM Interpret NUM as a LogEst and push onto stack\n"
" x Multiple the top two elements of the stack\n"
" + Add the top two elements of the stack\n"
" dup Dupliate the top element on the stack\n"
" inv Take the reciprocal of the top of stack. N = 1/N.\n"
" log Find the LogEst of the number on top of stack\n"
" nlogn Compute NlogN where N is the top of stack\n"
);
exit(1);
}
int main(int argc, char **argv){
@@ -111,30 +124,43 @@ int main(int argc, char **argv){
LogEst a[100];
for(i=1; i<argc; i++){
const char *z = argv[i];
if( z[0]=='+' ){
if( strcmp(z,"+")==0 ){
if( n>=2 ){
a[n-2] = logEstAdd(a[n-2],a[n-1]);
n--;
}
}else if( z[0]=='x' ){
}else if( strcmp(z,"x")==0 ){
if( n>=2 ){
a[n-2] = logEstMultiply(a[n-2],a[n-1]);
n--;
}
}else if( strcmp(z,"dup")==0 ){
if( n>0 ){
a[n] = a[n-1];
n++;
}
}else if( strcmp(z,"log")==0 ){
if( n>0 ) a[n-1] = logEstFromInteger(a[n-1]) - 33;
}else if( strcmp(z,"nlogn")==0 ){
if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33;
}else if( strcmp(z,"inv")==0 ){
if( n>0 ) a[n-1] = -a[n-1];
}else if( z[0]=='^' ){
a[n++] = atoi(z+1);
}else if( isFloat(z) ){
}else if( isInteger(z) ){
a[n++] = logEstFromInteger(atoi(z));
}else if( isFloat(z) && z[0]!='-' ){
a[n++] = logEstFromDouble(atof(z));
}else{
a[n++] = logEstFromInteger(atoi(z));
showHelp(argv[0]);
}
}
for(i=n-1; i>=0; i--){
if( a[i]<0 ){
printf("%d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
}else{
sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
printf("%d (%lld.%02lld)\n", a[i], x/100, x%100);
printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
}
}
return 0;
+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