Compare commits

..

70 Commits

Author SHA1 Message Date
dan ea933f07b0 Experimental fix for resetting databases that have been deemed read-only due
to a corrupt "read-version" header field.

FossilOrigin-Name: e2394002d02754bb45d56e805df9bc5a2ef0d14e5d94262c1f8ab7643bc27c8f
2018-07-19 11:44:02 +00:00
drh ea99a31c59 Add the SQLITE_FCNTL_DATA_VERSION file control
FossilOrigin-Name: a5087c5c87ad65f92e3bc96bbc84afb43faf10ab6b9ed3ba16304b5c60ad069f
2018-07-18 19:09:07 +00:00
drh 378a2da91e Fix a harmless compiler warning in the pager. Enhance the docs for
sqlite3_changes() and sqlite3_total_changes() to refer to the data_version
pragma.

FossilOrigin-Name: 4c70ea5b0e2a512c6a46ac1f14397720e8c8556875701e78c30b19f850c24f55
2018-07-18 17:37:51 +00:00
dan ac306682df If an SQLITE_IOERR error is encountered as part of an atomic commit on an F2FS file-system, retry the commit in legacy journal mode.
FossilOrigin-Name: 2e0357c2ed30927921cd17129e348a18a6f3fd086d1fc0a42756036b321a084d
2018-07-17 14:01:55 +00:00
dan 4522c3e8d1 Fix for builds without SQLITE_ENABLE_BATCH_ATOMIC_WRITE.
FossilOrigin-Name: b10ec14ef7edcc5d7b0ad298c8230d1eca5508e8cf673fbbc97a0928b76c92fb
2018-07-17 13:55:08 +00:00
dan e79522633a Add new file doc/F2FS.txt, containing notes on the way SQLite uses the F2FS atomic commit feature.
FossilOrigin-Name: 59efb1bfaba12742379aae45c8c796ca539f089af9e553a3a55d6899a9c583c8
2018-07-16 20:44:00 +00:00
drh 7f32dc94a3 Minor simplification to sqlite3RollbackAll().
FossilOrigin-Name: 432fdc221550b3cca4140b1ae411da22201f689c30c72c5472dfdbc79bec9d90
2018-07-16 11:32:59 +00:00
dan 140a59874b If an SQLITE_IOERR error is encountered as part of an atomic commit on an F2FS
file-system, retry the commit in legacy journal mode.

FossilOrigin-Name: 1c41250f67ac5de423b0426ef2ab8fe3303278a270225920033933ca9609592a
2018-07-14 20:25:13 +00:00
dan 2f69b5c5d0 Remove an unused function declaration from fts5.
FossilOrigin-Name: 148d9b61471a874a16a9ec9c9603da03cadb3a40662fb550af51cb36212426b1
2018-07-13 20:28:54 +00:00
dan b80bb6ce88 Add the "categories" option to the unicode61 tokenizer in fts5.
FossilOrigin-Name: 80d2b9e635e3100f90cffdcffa5b5038da6fbbfccc9f5777c59a4ae760d4cb62
2018-07-13 19:52:43 +00:00
dan e882551935 Add a test-control to disable the skip-scan optimization.
FossilOrigin-Name: 650a3fe03d61068e06f3097878a777ca8ed713a769444cdb3f8be7d1e19a0b83
2018-07-12 19:14:39 +00:00
dan 7490128240 Add a test case to check that SQLITE_DBCONFIG_RESET_DATABASE can be used with
wal mode databases even if there are active readers.

FossilOrigin-Name: 6145f5b3bacdee8f377892ac8b885941336c4cc543052f6373e21c1f99e1eca8
2018-07-12 11:28:42 +00:00
drh 222a384a06 On an UPSERT when the order of constraint checks is rearranged, make sure
that the affinity transformations on the inserted content occur before
any of the constraint checks.  Fix for ticket [79cad5e4b2e219dd197242e9e5f4e].

FossilOrigin-Name: d120c45f3dc79f67afed0e44e5133569f784bc6792b15f5d79529deac2d13072
2018-07-11 13:34:24 +00:00
drh 9341916ed5 Adjustments to VdbeCoverage macros to deal with byte-code branches that
can never be taken in some directions.

FossilOrigin-Name: b170c0092b1d0c47dd700843f0c870e51181939607a897fbcae55a58042160f9
2018-07-11 03:27:52 +00:00
drh 5d6374fa39 Remove incorrect ALWAYS() macros from the window function logic.
FossilOrigin-Name: 94ac51cc4e7fdf484214e1936fc96104b96134632a8eb99558b3af743ac8bb8b
2018-07-10 23:31:17 +00:00
drh c3649417fe Add VdbeModuleComment()s on the three main code generators for window
functions.

FossilOrigin-Name: f7c239e959004cb90dc8537ab2e1fca5f26ef21f4f6f3dfd743a05a55e705090
2018-07-10 22:24:14 +00:00
drh b0225bc52d Minor comment changes. Add ALWAYS() macros on some unreachable branches
in the xStep() methods of built-in window functions.

FossilOrigin-Name: f2057542cf6860badb4ae6b1a0df94a78d5b2661dabf16f5705b3f8236521bea
2018-07-10 20:50:27 +00:00
drh fef37760da Identify Select objects within a single statement using small sequential
integers rather than "0x%p".  This is more readable and yields the same result
on successive runs.

FossilOrigin-Name: a7cdc5bc85e0edfcc38f920c2ce91599bcbfdb49522d88b08c64596546d13881
2018-07-10 19:48:35 +00:00
dan fd908888d3 Modify tests in window3.test to be tolerant of rounding errors when comparing
floating point values.

FossilOrigin-Name: 7c26c443e7f6455ca7f11f640e42285b42d95c9ae5f2e19e9c066d6d9cdcceb2
2018-07-10 18:50:01 +00:00
dan b556f26145 Fix a problem with using scalar sub-selects in window function queries.
FossilOrigin-Name: 687fe532c274265ca77451f97829743fcb8a714d0f6b1ceb9a147ab9babdc5b5
2018-07-10 17:26:12 +00:00
drh 6ccbd2787b Further improvements to bytecode branch testing. Fix cases where the
macros said a branch could not be taken when in fact it could be.  Alter
some window function branch coverage macros to indicate that comparison
operands cannot be NULL.

FossilOrigin-Name: 76e42b7071a71137c0da4f10db4e653ae94a89b56e95cd3f036bff08c9500d08
2018-07-10 17:10:44 +00:00
drh 7083a487ad Enhancements and improved documentation to the byte-code branch coverage
testing logic.  Provide new macros that allow the code to specify that
some branch instructions can never take the NULL path and that the OP_Jump
opcode is only interested in equal/not-equal.  The
SQLITE_TESTCTRL_VDBE_COVERAGE file control callback now works slightly
differently (it provides the callback with a bitmask of the branch action,
rather than an integer).

FossilOrigin-Name: cd2da7e1ba4e78e68ccf65d4969df963c1e3085930e74419450bda2799381e05
2018-07-10 16:04:04 +00:00
drh eee0861155 Fix a harmless warning about comment formatting in the previous
check-in.  Simplify the ORDER BY dereferencing logic so that it avoids
unreachable branches.

FossilOrigin-Name: 0f6ec605e131ab3d53b9df32af0a3207146a9abbd22dcabd6ef050b92f96735d
2018-07-10 07:39:23 +00:00
drh 38630ae1de Assert that if two functions compare equal in every other way, then they
must both have OVER clauses, or neither has an OVER clause.  Use this fact
to simplify expression comparison.

FossilOrigin-Name: 52559ad58ce412af40f1f34e80bfe9fadc6a93f3ca0cfaf69f94d615bbb99831
2018-07-10 07:25:42 +00:00
drh 6cbb4c936c Enhance the sqlite3ExprCompare() routine so that it knows to compare the
OVER clause of window functions.

FossilOrigin-Name: 0a7649afebc9349bf44a0e3588e81ab595ea85be1c70de08859ea76a7b271f62
2018-07-10 06:47:07 +00:00
drh a1fd4b520b Enhance the TreeView mechanism so that it shows the window function
data structures as part of the abstract syntax tree.

FossilOrigin-Name: a2c0e1bec0d8a6f982572c4c5a8166319b8db0fe586057f7900f0ab72af6554e
2018-07-10 06:32:53 +00:00
drh 0b3b0dd1b1 New VDBE comments and coverage macros.
FossilOrigin-Name: a9a307265b0626b3e9df69534c8eacf18413ea31784c9d931eadcff515d3dd84
2018-07-10 05:11:03 +00:00
drh c7bf57168a Fixes for various harmless compiler warnings.
FossilOrigin-Name: 5023b1b85b883a716a5da673740b6effe214ee0490f4ca45f161bb8b04784366
2018-07-09 22:49:01 +00:00
drh 142066d4b0 Add a comment to restriction (6) of the push-down optimization. No changes
to code.

FossilOrigin-Name: 0c8a2f257fb71b2b053c4a2028db063e92dd9ff585a17fa22a70f9223fb11e75
2018-07-09 20:58:43 +00:00
drh f710345303 Add an ALWAYS() around a branch in sqlite3BtreeSkipNext() that we believe
must always be true.

FossilOrigin-Name: 12be361a532df0c22a7e4d97658b82a69b1a205d4cca8d092b9e6b7790c1ee40
2018-07-09 20:41:39 +00:00
dan 77f3f40292 Avoid leaving view-definitions with an incomplete set of column names/types in
the in-memory schema if an OOM strikes while allocating the same.

FossilOrigin-Name: 1ddbb5372e7ea8407369b88698b3fb922b62dcac72be633a17bd0e41baa369f4
2018-07-09 18:55:44 +00:00
dan e6fcd1d5de Add a couple of OOM tests.
FossilOrigin-Name: 50de2a0d2d96b6b5b8de7ac6277d60859a8d9a56f6a792950734386bb9f10b79
2018-07-09 18:11:52 +00:00
drh 7999cc434e Remove redundant branches in window function processing.
FossilOrigin-Name: 8fdaf3f37e5ddac9b7337a50f32f5d2bcdd64780797f08cfd3fccfa95819edfe
2018-07-09 17:33:24 +00:00
drh a57aac262f Simplification to the grammar rules for window functions. Fix a memory
leak that can follow an OOM while parsing a comma-separated list of
window definitions.

FossilOrigin-Name: a568f9c9db594f3b194c6e870305c9d6f2392ce6bc8ac00e9688883e97560fff
2018-07-09 16:24:00 +00:00
dan a1a7e112fe Throw an error if the second argument passed to nth_value() is not a positive
integer.

FossilOrigin-Name: 1a06e57a0b4279fa580c7ff4f152645f005794aaf86eeabf694637b7da11f763
2018-07-09 13:31:18 +00:00
dan f5e8e31399 Fix a bad assert() in window.c.
FossilOrigin-Name: fe8aaf0c806413965f50a03e34b5fdfaaa8b09dc0af73f41e830f7b664bd1ced
2018-07-09 06:51:36 +00:00
drh 1e80ace47a Simplification to the logic that detects misuse of the application-defined
function creation interfaces.

FossilOrigin-Name: 8f21d778450e1e5d2bc7f109d614fe018eb3d228b0bfc91cd3c6a5204415998f
2018-07-09 02:37:12 +00:00
drh 8ff21f47f0 During WITHOUT ROWID table creation, if the sqlite3CreateTable() call fails
due to an authorizer denying the INSERT into the sqlite_master table, then
detect this fact and abort the CREATE TABLE early, to avoid an assertion
fault.

FossilOrigin-Name: 164b1641e346994f0b9f91261c3cbc86b68e1c96cc401b78e48e186e26916abe
2018-07-09 02:02:09 +00:00
drh 19dc4d40e7 Identify specific FuncDef objects for window functions using the pointer to
the function name (FuncDef.zName) rather than the pointer to the xStep method.
This allows xStep method pointer to be replaced with a single noopStepFunc()
procedure, and thus save having lots of different no-op step functions.

FossilOrigin-Name: 410e13b0e0fb6e040808f076014d55ecf2b541c5439b4fd53c5bdcb8d800098e
2018-07-08 01:02:26 +00:00
drh a546ef219e Simplifications to the implementation of the sum() SQL function.
FossilOrigin-Name: a8b13002378fc4ef0b41c367b44b67bf2b28b6624303c087a3c6d657b5bfe32e
2018-07-07 20:55:16 +00:00
dan 51a6b19337 Fix another problem with reusing LSM cursors for range scans.
FossilOrigin-Name: ae3fc7652f27ba0a86f4c26f64c2e148d9496a5edb7f54dc9980edd91c326e4f
2018-07-07 20:26:30 +00:00
drh 491d4c89f5 Fix the JSON extension so that it can be compiled separately from the
amalgamation.

FossilOrigin-Name: 4b8cfe7bfe5f049eb4607fd480429fcd2060e691891d8bffc9917f13fa373988
2018-07-07 20:23:46 +00:00
dan 8f0c712a1f Fix an LSM problem caused by using the same cursor for equality and range
scans.

FossilOrigin-Name: f05bead371d41ca5beef1f82e4c920c90e2eb9cd9fd537a5c91973bf9bd4eedb
2018-07-07 20:13:32 +00:00
drh fd4b72853a Add ALWAYS() macros on results of sqlite3_aggregate_context() calls in
xInverse() implements, since they can never fail.

FossilOrigin-Name: fdef2a921d451c66ca535021d08af3ec1ab53283da2d2979378a799fd8731ef9
2018-07-07 19:47:21 +00:00
drh 2c885d0575 Add an assert() to help verify that OP_AggInverse is never called on an
accumulator that has not previously been processed by OP_AggStep.

FossilOrigin-Name: 4213889103fa37f3f11802aea81989522048a0752820603dd556f612128ddfee
2018-07-07 19:36:04 +00:00
dan a5ef149c4e Add missing VdbeCoverage() macro to window.c.
FossilOrigin-Name: 63f4d306ba19f6ba900a7d7480ccaa3d1e4a204e7c82bf5eb2e4bd849ef3a22f
2018-07-07 17:38:49 +00:00
dan d4fc49f735 Fix a problem with the handling of NULL values in the min() window function.
FossilOrigin-Name: b76f35b09235d44dc3d176377bbb9c18b7cdc9392800103ff53c54730a427a5c
2018-07-07 17:30:44 +00:00
drh e4984a2bf4 Try to improve the error messages for misformed frame specifications in
window definitions.

FossilOrigin-Name: 927b95a0812787bcb3c28d1a0ea94717dc2cc60f6d480623f0c7cbce0c546fc9
2018-07-06 17:19:20 +00:00
dan bfead59b3b Also disallow non-constant expressions in "<expr> PRECEDING" or "<expr>
FOLLOWING" clauses.

FossilOrigin-Name: a6dffecc6b35c618cc5e5a06892765bdbec587dcd0ae8686c231a21516e38eab
2018-07-06 14:31:26 +00:00
dan 5d764ac9e6 Ensure an error is returned if the user specifies an unsupported frame type.
FossilOrigin-Name: 0f3f8fcde1a535bcf93e23a68d2411c21785d8c0cac1f9481a06e7225755cdbc
2018-07-06 14:15:49 +00:00
dan 287fa17b78 Prevent "UNBOUNDED FOLLOWING" from being used as the starting boundary of a
window-frame. And "UNBOUNDED PRECEDING" from being used as the ending
boundary.

FossilOrigin-Name: e51fdf66a24c27ba6491391fffcc88fc5ca2ae79cfc4ab769a149b19c394e308
2018-07-06 13:48:09 +00:00
dan cf0343b699 Remove some bad assert() statements from the implementations of window
functions percent_rank() and cume_dist().

FossilOrigin-Name: 443f0c286f1659937fd61b4ef2de17d0d015369e5ff5249a9e0c3d0ee4925158
2018-07-06 13:25:02 +00:00
dan e33f6e7c91 Return an error if DISTINCT is used with a window-function (.i.e.
"count(DISTINCT <expr>) OVER (...)".

FossilOrigin-Name: d59bcc8eea4fcf0ee3c2263d31ee42f9f26c28434d2f0045f2d3329f18791d1c
2018-07-06 07:42:42 +00:00
drh 8f26da6c5b Use separate opcodes, OP_AggValue and OP_AggInverse, for the new callbacks
associated with Window Functions, for improved readability of EXPLAIN
output.

FossilOrigin-Name: fa6538050938ffeb042fbee31512514d6d3ace514b2a3dfd8365bbeb13f35a78
2018-07-05 21:22:57 +00:00
dan 6ea9a7282a Update the recipe for resetting a database using
SQLITE_DBCONFIG_RESET_DATABASE.

FossilOrigin-Name: c43dd23fb00f7e0b6274de435d8e31f6a4cb74c3e86e8313a5098ff089e27574
2018-07-05 20:33:06 +00:00
drh 8be47a7e86 Get the json_group_array() and json_group_object() SQL functions working
as window functions.

FossilOrigin-Name: 916cdc83f5a45e0b6f61c52ff5fde70d54bcd0dfaa4a32f9ac709fe0ddbb480b
2018-07-05 20:05:29 +00:00
dan 7a606e1ab2 Return an error if a "RANGE" window-frame uses "<expr> PRECEDING" or "<expr>
FOLLOWING".

FossilOrigin-Name: 786c87ba4150509e141baab32c51e64bbd3ce323735e0f47d65ed54d14215bc4
2018-07-05 18:34:53 +00:00
dan 683b0fffee Fix a problem in the xInverse method of window-function group_concat(1).
FossilOrigin-Name: 73391283101288251fe5d030ba12bcdabe8a781d41086afe3564c58c05d0fd5c
2018-07-05 18:19:29 +00:00
drh f213b33c37 Fix the .dump command in the command-line shell so that it does not show
extraneous SELECT statements when ".echo on" is enabled.

FossilOrigin-Name: 11763cac33fa809bcf0294d1a381394fcf860b020b51fff81217ee709ba99272
2018-07-05 17:35:46 +00:00
dan 8bf6d705f3 In wal mode, if a "BEGIN EXCLUSIVE" command (or any other command that
upgrades from no transaction directly to a write transaction) hits an
SQLITE_BUSY_SNAPSHOT error, change the error code to SQLITE_BUSY to indicate
to the caller that the condition may be transient.

FossilOrigin-Name: e6108047cb136119d8ed19af010a669ed9750b4e7f991ccabc9e3d15774eda31
2018-07-05 17:16:55 +00:00
dan b775104357 Fix a typo inside an assert() statement introduced by the previous commit.
FossilOrigin-Name: e3357728472d5e57db6d7eef0ce008bdee071b5b07b60e242f383440eebe85bd
2018-07-05 17:03:43 +00:00
dan b07db116e7 In wal mode, if a "BEGIN EXCLUSIVE" command (or any other command that
upgrades from no transaction directly to a write transaction) hits an
SQLITE_BUSY_SNAPSHOT error, change the error code to SQLITE_BUSY to indicate
to the caller that the condition may be transient.

FossilOrigin-Name: 221ff63e7902226ebf728bb7442727420636831163708f360724506ce9487ab6
2018-07-05 15:46:55 +00:00
dan 7fee0bfad2 Test that a race condition can cause a "BEGIN EXCLUSIVE" to return
SQLITE_BUSY_SNAPSHOT in wal mode.

FossilOrigin-Name: 5a12db75d1da65daa92413a6b5892309e9d9479bb3610764e1015abe5bf28dbe
2018-07-03 20:17:27 +00:00
dan d736829e8b Fix a problem in the xInverse callback for the built-in sum() window function.
FossilOrigin-Name: b6563647382634588ebe5c6a3c35c65a321dc1b3732c809d48ce46759b9dd80f
2018-07-02 17:45:59 +00:00
dan f607bec749 Fix a segfault caused by having identical window functions in the select-list
and ORDER BY clause of a SELECT statement.

FossilOrigin-Name: 693b4350d741391226a33ab6a05eaad61e8ef1590176f01e8aed2a212e2d6419
2018-07-02 17:14:37 +00:00
dan 6b4b88208e Fix a crash caused by a LIKE pattern that consists of a single escape
character.

FossilOrigin-Name: bb9bfc3a12dfb89b1c58f5551cdc89ab7b0fbe03f285f2ed86611786ed02ffd9
2018-07-02 15:03:50 +00:00
dan 7262ca94cb Fix a segfault caused by invoking a regular aggregate as a window-function.
And some problems with count(*) when used as a window-function.

FossilOrigin-Name: 4f3c8a82fd1c5b14d84f2301e34cfc8d52fe4b3a60840c39e895c11f2da529d9
2018-07-02 12:07:32 +00:00
drh 9f607e9c23 Quick patch to the Lemon parser template to avoid an array overread reported
by OSSFuzz.  A proper fix involves enhancements to the table generators in
Lemon to make the overread impossible.  That fix will take longer to
implement.  The current check-in is a stop-gap.

FossilOrigin-Name: 3f6730be4cb712a28401be6d96e56ccb3f2e98dd8961b477befec3f363715178
2018-07-01 16:05:40 +00:00
dan d2ac43ea38 Avoid a warning in fts5.c due to not using generated routine
sqlite3Fts5ParserFallback().

FossilOrigin-Name: 65ff5144a55f1ba2b2ef812a0c988fa2522441177038b8d686eb1d0c558c75d5
2018-06-30 20:26:52 +00:00
dan 9592320b91 Merge implementation of SQL window functions from the exp-window-functions
into trunk.

FossilOrigin-Name: 17198a1206e2fbc9e555881468e8c6980b00e25b5b78a6798a6264ca7384f1ca
2018-06-30 20:15:58 +00:00
61 changed files with 7399 additions and 2742 deletions
+87
View File
@@ -0,0 +1,87 @@
SQLite's OS layer contains the following definitions used in F2FS related
calls:
#define F2FS_IOCTL_MAGIC 0xf5
#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
After opening a database file on Linux (including Android), SQLite determines
whether or not a file supports F2FS atomic commits as follows:
u32 flags = 0;
rc = ioctl(fd, F2FS_IOC_GET_FEATURES, &flags);
if( rc==0 && (flags & F2FS_FEATURE_ATOMIC_WRITE) ){
/* File supports F2FS atomic commits */
}else{
/* File does NOT support F2FS atomic commits */
}
where "fd" is the file-descriptor open on the database file.
Usually, when writing to a database file that supports atomic commits, SQLite
accumulates the entire transaction in heap memory, deferring all writes to the
db file until the transaction is committed.
When it is time to commit a transaction on a file that supports atomic
commits, SQLite does:
/* Take an F_WRLCK lock on the database file. This prevents any other
** SQLite clients from reading or writing the file until the lock
** is released. */
rc = fcntl(fd, F_SETLK, ...);
if( rc!=0 ) goto failed;
rc = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE);
if( rc!=0 ) goto fallback_to_legacy_journal_commit;
foreach (dirty page){
rc = write(fd, ...dirty page...);
if( rc!=0 ){
ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
goto fallback_to_legacy_journal_commit;
}
}
rc = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE);
if( rc!=0 ){
ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE);
goto fallback_to_legacy_journal_commit;
}
/* If we get there, the transaction has been successfully
** committed to persistent storage. The following call
** relinquishes the F_WRLCK lock. */
fcntl(fd, F_SETLK, ...);
Assumptions:
1. After either of the F2FS_IOC_ABORT_VOLATILE_WRITE calls return,
the database file is in the state that it was in before
F2FS_IOC_START_ATOMIC_WRITE was invoked. Even if the ioctl()
fails - we're ignoring the return code.
This is true regardless of the type of error that occurred in
ioctl() or write().
2. If the system fails before the F2FS_IOC_COMMIT_ATOMIC_WRITE is
completed, then following a reboot the database file is in the
state that it was in before F2FS_IOC_START_ATOMIC_WRITE was invoked.
Or, if the write was commited right before the system failed, in a
state indicating that all write() calls were successfully committed
to persistent storage before the failure occurred.
3. If the process crashes before the F2FS_IOC_COMMIT_ATOMIC_WRITE is
completed then the file is automatically restored to the state that
it was in before F2FS_IOC_START_ATOMIC_WRITE was called. This occurs
before the posix advisory lock is automatically dropped - there is
no chance that another client will be able to read the file in a
half-committed state before the rollback operation occurs.
+284 -4
View File
@@ -529,6 +529,263 @@ proc print_fold {zFunc} {
puts "\}"
}
proc code {txt} {
set txt [string trimright $txt]
set txt [string trimleft $txt "\n"]
set n [expr {[string length $txt] - [string length [string trim $txt]]}]
set ret ""
foreach L [split $txt "\n"] {
append ret "[string range $L $n end]\n"
}
return [uplevel "subst -nocommands {$ret}"]
}
proc intarray {lInt} {
set ret ""
set n [llength $lInt]
for {set i 0} {$i < $n} {incr i 10} {
append ret "\n "
foreach int [lrange $lInt $i [expr $i+9]] {
append ret [format "%-7s" "$int, "]
}
}
append ret "\n "
set ret
}
proc categories_switch {Cvar first lSecond} {
upvar $Cvar C
set ret ""
append ret "case '$first':\n"
append ret " switch( zCat\[1\] ){\n"
foreach s $lSecond {
append ret " case '$s': aArray\[$C($first$s)\] = 1; break;\n"
}
append ret " case '*': \n"
foreach s $lSecond {
append ret " aArray\[$C($first$s)\] = 1;\n"
}
append ret " break;\n"
append ret " default: return 1;"
append ret " }\n"
append ret " break;\n"
}
# Argument is a list. Each element of which is itself a list of two elements:
#
# * the codepoint
# * the category
#
# List elements are sorted in order of codepoint.
#
proc print_categories {lMap} {
set categories {
Cc Cf Cn Cs
Ll Lm Lo Lt Lu
Mc Me Mn
Nd Nl No
Pc Pd Pe Pf Pi Po Ps
Sc Sk Sm So
Zl Zp Zs
LC Co
}
for {set i 0} {$i < [llength $categories]} {incr i} {
set C([lindex $categories $i]) [expr 1+$i]
}
set caseC [categories_switch C C {c f n s o}]
set caseL [categories_switch C L {l m o t u C}]
set caseM [categories_switch C M {c e n}]
set caseN [categories_switch C N {d l o}]
set caseP [categories_switch C P {c d e f i o s}]
set caseS [categories_switch C S {c k m o}]
set caseZ [categories_switch C Z {l p s}]
set nCat [expr [llength [array names C]] + 1]
puts [code {
int sqlite3Fts5UnicodeNCat(void) {
return $nCat;
}
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
aArray[0] = 1;
switch( zCat[0] ){
$caseC
$caseL
$caseM
$caseN
$caseP
$caseS
$caseZ
}
return 0;
}
}]
set nRepeat 0
set first [lindex $lMap 0 0]
set class [lindex $lMap 0 1]
set prev -1
set CASE(0) "Lu"
set CASE(1) "Ll"
foreach m $lMap {
foreach {codepoint cl} $m {}
set codepoint [expr "0x$codepoint"]
if {$codepoint>=(1<<20)} continue
set bNew 0
if {$codepoint!=($prev+1)} {
set bNew 1
} elseif {
$cl==$class || ($class=="LC" && $cl==$CASE([expr $nRepeat & 0x01]))
} {
incr nRepeat
} elseif {$class=="Lu" && $nRepeat==1 && $cl=="Ll"} {
set class LC
incr nRepeat
} else {
set bNew 1
}
if {$bNew} {
lappend lEntries [list $first $class $nRepeat]
set nRepeat 1
set first $codepoint
set class $cl
}
set prev $codepoint
}
if {$nRepeat>0} {
lappend lEntries [list $first $class $nRepeat]
}
set aBlock [list 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
set aMap [list]
foreach e $lEntries {
foreach {cp class nRepeat} $e {}
set block [expr ($cp>>16)]
if {$block>0 && [lindex $aBlock $block]==0} {
for {set i 1} {$i<=$block} {incr i} {
if {[lindex $aBlock $i]==0} {
lset aBlock $i [llength $aMap]
}
}
}
lappend aMap [expr {$cp & 0xFFFF}]
lappend aData [expr {($nRepeat << 5) + $C($class)}]
}
for {set i 1} {$i<[llength $aBlock]} {incr i} {
if {[lindex $aBlock $i]==0} {
lset aBlock $i [llength $aMap]
}
}
set aBlockArray [intarray $aBlock]
set aMapArray [intarray $aMap]
set aDataArray [intarray $aData]
puts [code {
static u16 aFts5UnicodeBlock[] = {$aBlockArray};
static u16 aFts5UnicodeMap[] = {$aMapArray};
static u16 aFts5UnicodeData[] = {$aDataArray};
int sqlite3Fts5UnicodeCategory(int iCode) {
int iRes = -1;
int iHi;
int iLo;
int ret;
u16 iKey;
if( iCode>=(1<<20) ){
return 0;
}
iLo = aFts5UnicodeBlock[(iCode>>16)];
iHi = aFts5UnicodeBlock[1+(iCode>>16)];
iKey = (iCode & 0xFFFF);
while( iHi>iLo ){
int iTest = (iHi + iLo) / 2;
assert( iTest>=iLo && iTest<iHi );
if( iKey>=aFts5UnicodeMap[iTest] ){
iRes = iTest;
iLo = iTest+1;
}else{
iHi = iTest;
}
}
if( iRes<0 ) return 0;
if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
ret = aFts5UnicodeData[iRes] & 0x1F;
if( ret!=$C(LC) ) return ret;
return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? $C(Ll) : $C(Lu);
}
void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
int i = 0;
int iTbl = 0;
while( i<128 ){
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
for(; i<128 && i<n; i++){
aAscii[i] = bToken;
}
iTbl++;
}
}
}]
}
proc print_test_categories {lMap} {
set lCP [list]
foreach e $lMap {
foreach {cp cat} $e {}
if {[expr 0x$cp] < (1<<20)} {
lappend lCP "{0x$cp, \"$cat\"}, "
}
}
set aCP "\n"
for {set i 0} {$i < [llength $lCP]} {incr i 4} {
append aCP " [join [lrange $lCP $i $i+3]]\n"
}
puts [code {
static int categories_test (int *piCode){
struct Codepoint {
int iCode;
const char *zCat;
} aCP[] = {$aCP};
int i;
int iCP = 0;
for(i=0; i<1000000; i++){
u8 aArray[40];
int cat = 0;
int c = 0;
memset(aArray, 0, sizeof(aArray));
if( aCP[iCP].iCode==i ){
sqlite3Fts5UnicodeCatParse(aCP[iCP].zCat, aArray);
iCP++;
}else{
aArray[0] = 1;
}
c = sqlite3Fts5UnicodeCategory(i);
if( aArray[c]==0 ){
*piCode = i;
return 1;
}
}
return 0;
}
}]
}
proc print_fold_test {zFunc mappings} {
global tl_lookup_table
@@ -605,15 +862,21 @@ proc print_test_main {} {
puts "#include <stdio.h>"
puts ""
puts "int main(int argc, char **argv)\{"
puts " int r1, r2;"
puts " int r1, r2, r3;"
puts " int code;"
puts " r3 = 0;"
puts " r1 = isalnum_test(&code);"
puts " if( r1 ) printf(\"isalnum(): Problem with code %d\\n\",code);"
puts " else printf(\"isalnum(): test passed\\n\");"
puts " r2 = fold_test(&code);"
puts " if( r2 ) printf(\"fold(): Problem with code %d\\n\",code);"
puts " else printf(\"fold(): test passed\\n\");"
puts " return (r1 || r2);"
if {$::generate_fts5_code} {
puts " r3 = categories_test(&code);"
puts " if( r3 ) printf(\"categories(): Problem with code %d\\n\",code);"
puts " else printf(\"categories(): test passed\\n\");"
}
puts " return (r1 || r2 || r3);"
puts "\}"
}
@@ -651,10 +914,18 @@ for {set i 0} {$i < [llength $argv]-2} {incr i} {
print_fileheader
if {$::generate_test_code} {
puts "typedef unsigned short int u16;"
puts "typedef unsigned char u8;"
puts "#include <string.h>"
}
# Print the isalnum() function to stdout.
#
set lRange [an_load_separator_ranges]
print_isalnum ${function_prefix}UnicodeIsalnum $lRange
if {$generate_fts5_code==0} {
print_isalnum ${function_prefix}UnicodeIsalnum $lRange
}
# Leave a gap between the two generated C functions.
#
@@ -677,12 +948,21 @@ puts ""
#
print_fold ${function_prefix}UnicodeFold
if {$generate_fts5_code} {
puts ""
puts ""
print_categories [cc_load_unicodedata_text ${unicodedata.txt}]
}
# Print the test routines and main() function to stdout, if -test
# was specified.
#
if {$::generate_test_code} {
print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange
if {$generate_fts5_code==0} {
print_test_isalnum ${function_prefix}UnicodeIsalnum $lRange
}
print_fold_test ${function_prefix}UnicodeFold $mappings
print_test_categories [cc_load_unicodedata_text ${unicodedata.txt}]
print_test_main
}
+36
View File
@@ -143,4 +143,40 @@ proc tl_load_casefolding_txt {zName} {
}
}
proc cc_load_unicodedata_text {zName} {
set fd [open $zName]
set lField {
code
character_name
general_category
canonical_combining_classes
bidirectional_category
character_decomposition_mapping
decimal_digit_value
digit_value
numeric_value
mirrored
unicode_1_name
iso10646_comment_field
uppercase_mapping
lowercase_mapping
titlecase_mapping
}
set lRet [list]
while { ![eof $fd] } {
set line [gets $fd]
if {$line == ""} continue
set fields [split $line ";"]
if {[llength $fields] != [llength $lField]} { error "parse error: $line" }
foreach $lField $fields {}
lappend lRet [list $code $general_category]
}
close $fd
set lRet
}
+4 -1
View File
@@ -784,9 +784,12 @@ int sqlite3Fts5VocabInit(Fts5Global*, sqlite3*);
/**************************************************************************
** Interface to automatically generated code in fts5_unicode2.c.
*/
int sqlite3Fts5UnicodeIsalnum(int c);
int sqlite3Fts5UnicodeIsdiacritic(int c);
int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic);
int sqlite3Fts5UnicodeCatParse(const char*, u8*);
int sqlite3Fts5UnicodeCategory(int iCode);
void sqlite3Fts5UnicodeAscii(u8*, u8*);
/*
** End of interface to code in fts5_unicode2.c.
**************************************************************************/
+10 -2
View File
@@ -36,6 +36,7 @@ void sqlite3Fts5Parser(void*, int, Fts5Token, Fts5Parse*);
#include <stdio.h>
void sqlite3Fts5ParserTrace(FILE*, char*);
#endif
int sqlite3Fts5ParserFallback(int);
struct Fts5Expr {
@@ -2540,14 +2541,19 @@ static void fts5ExprIsAlnum(
sqlite3_value **apVal /* Function arguments */
){
int iCode;
u8 aArr[32];
if( nArg!=1 ){
sqlite3_result_error(pCtx,
"wrong number of arguments to function fts5_isalnum", -1
);
return;
}
memset(aArr, 0, sizeof(aArr));
sqlite3Fts5UnicodeCatParse("L*", aArr);
sqlite3Fts5UnicodeCatParse("N*", aArr);
sqlite3Fts5UnicodeCatParse("Co", aArr);
iCode = sqlite3_value_int(apVal[0]);
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeIsalnum(iCode));
sqlite3_result_int(pCtx, aArr[sqlite3Fts5UnicodeCategory(iCode)]);
}
static void fts5ExprFold(
@@ -2591,10 +2597,12 @@ int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
rc = sqlite3_create_function(db, p->z, -1, SQLITE_UTF8, pCtx, p->x, 0, 0);
}
/* Avoid a warning indicating that sqlite3Fts5ParserTrace() is unused */
/* Avoid warnings indicating that sqlite3Fts5ParserTrace() and
** sqlite3Fts5ParserFallback() are unused */
#ifndef NDEBUG
(void)sqlite3Fts5ParserTrace;
#endif
(void)sqlite3Fts5ParserFallback;
return rc;
}
+40 -4
View File
@@ -237,6 +237,8 @@ struct Unicode61Tokenizer {
int bRemoveDiacritic; /* True if remove_diacritics=1 is set */
int nException;
int *aiException;
unsigned char aCategory[32]; /* True for token char categories */
};
static int fts5UnicodeAddExceptions(
@@ -261,7 +263,7 @@ static int fts5UnicodeAddExceptions(
if( iCode<128 ){
p->aTokenChar[iCode] = (unsigned char)bTokenChars;
}else{
bToken = sqlite3Fts5UnicodeIsalnum(iCode);
bToken = p->aCategory[sqlite3Fts5UnicodeCategory(iCode)];
assert( (bToken==0 || bToken==1) );
assert( (bTokenChars==0 || bTokenChars==1) );
if( bToken!=bTokenChars && sqlite3Fts5UnicodeIsdiacritic(iCode)==0 ){
@@ -322,6 +324,21 @@ static void fts5UnicodeDelete(Fts5Tokenizer *pTok){
return;
}
static int unicodeSetCategories(Unicode61Tokenizer *p, const char *zCat){
const char *z = zCat;
while( *z ){
while( *z==' ' || *z=='\t' ) z++;
if( *z && sqlite3Fts5UnicodeCatParse(z, p->aCategory) ){
return SQLITE_ERROR;
}
while( *z!=' ' && *z!='\t' && *z!='\0' ) z++;
}
sqlite3Fts5UnicodeAscii(p->aCategory, p->aTokenChar);
return SQLITE_OK;
}
/*
** Create a "unicode61" tokenizer.
*/
@@ -340,15 +357,28 @@ static int fts5UnicodeCreate(
}else{
p = (Unicode61Tokenizer*)sqlite3_malloc(sizeof(Unicode61Tokenizer));
if( p ){
const char *zCat = "L* N* Co";
int i;
memset(p, 0, sizeof(Unicode61Tokenizer));
memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar));
p->bRemoveDiacritic = 1;
p->nFold = 64;
p->aFold = sqlite3_malloc(p->nFold * sizeof(char));
if( p->aFold==0 ){
rc = SQLITE_NOMEM;
}
/* Search for a "categories" argument */
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
zCat = azArg[i+1];
}
}
if( rc==SQLITE_OK ){
rc = unicodeSetCategories(p, zCat);
}
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
@@ -362,10 +392,14 @@ static int fts5UnicodeCreate(
}else
if( 0==sqlite3_stricmp(azArg[i], "separators") ){
rc = fts5UnicodeAddExceptions(p, zArg, 0);
}else
if( 0==sqlite3_stricmp(azArg[i], "categories") ){
/* no-op */
}else{
rc = SQLITE_ERROR;
}
}
}else{
rc = SQLITE_NOMEM;
}
@@ -384,8 +418,10 @@ static int fts5UnicodeCreate(
** character (not a separator).
*/
static int fts5UnicodeIsAlnum(Unicode61Tokenizer *p, int iCode){
assert( (sqlite3Fts5UnicodeIsalnum(iCode) & 0xFFFFFFFE)==0 );
return sqlite3Fts5UnicodeIsalnum(iCode) ^ fts5UnicodeIsException(p, iCode);
return (
p->aCategory[sqlite3Fts5UnicodeCategory(iCode)]
^ fts5UnicodeIsException(p, iCode)
);
}
static int fts5UnicodeTokenize(
+533 -129
View File
@@ -18,135 +18,6 @@
#include <assert.h>
/*
** Return true if the argument corresponds to a unicode codepoint
** classified as either a letter or a number. Otherwise false.
**
** The results are undefined if the value passed to this function
** is less than zero.
*/
int sqlite3Fts5UnicodeIsalnum(int c){
/* Each unsigned integer in the following array corresponds to a contiguous
** range of unicode codepoints that are not either letters or numbers (i.e.
** codepoints for which this function should return 0).
**
** The most significant 22 bits in each 32-bit value contain the first
** codepoint in the range. The least significant 10 bits are used to store
** the size of the range (always at least 1). In other words, the value
** ((C<<22) + N) represents a range of N codepoints starting with codepoint
** C. It is not possible to represent a range larger than 1023 codepoints
** using this format.
*/
static const unsigned int aEntry[] = {
0x00000030, 0x0000E807, 0x00016C06, 0x0001EC2F, 0x0002AC07,
0x0002D001, 0x0002D803, 0x0002EC01, 0x0002FC01, 0x00035C01,
0x0003DC01, 0x000B0804, 0x000B480E, 0x000B9407, 0x000BB401,
0x000BBC81, 0x000DD401, 0x000DF801, 0x000E1002, 0x000E1C01,
0x000FD801, 0x00120808, 0x00156806, 0x00162402, 0x00163C01,
0x00164437, 0x0017CC02, 0x00180005, 0x00181816, 0x00187802,
0x00192C15, 0x0019A804, 0x0019C001, 0x001B5001, 0x001B580F,
0x001B9C07, 0x001BF402, 0x001C000E, 0x001C3C01, 0x001C4401,
0x001CC01B, 0x001E980B, 0x001FAC09, 0x001FD804, 0x00205804,
0x00206C09, 0x00209403, 0x0020A405, 0x0020C00F, 0x00216403,
0x00217801, 0x0023901B, 0x00240004, 0x0024E803, 0x0024F812,
0x00254407, 0x00258804, 0x0025C001, 0x00260403, 0x0026F001,
0x0026F807, 0x00271C02, 0x00272C03, 0x00275C01, 0x00278802,
0x0027C802, 0x0027E802, 0x00280403, 0x0028F001, 0x0028F805,
0x00291C02, 0x00292C03, 0x00294401, 0x0029C002, 0x0029D401,
0x002A0403, 0x002AF001, 0x002AF808, 0x002B1C03, 0x002B2C03,
0x002B8802, 0x002BC002, 0x002C0403, 0x002CF001, 0x002CF807,
0x002D1C02, 0x002D2C03, 0x002D5802, 0x002D8802, 0x002DC001,
0x002E0801, 0x002EF805, 0x002F1803, 0x002F2804, 0x002F5C01,
0x002FCC08, 0x00300403, 0x0030F807, 0x00311803, 0x00312804,
0x00315402, 0x00318802, 0x0031FC01, 0x00320802, 0x0032F001,
0x0032F807, 0x00331803, 0x00332804, 0x00335402, 0x00338802,
0x00340802, 0x0034F807, 0x00351803, 0x00352804, 0x00355C01,
0x00358802, 0x0035E401, 0x00360802, 0x00372801, 0x00373C06,
0x00375801, 0x00376008, 0x0037C803, 0x0038C401, 0x0038D007,
0x0038FC01, 0x00391C09, 0x00396802, 0x003AC401, 0x003AD006,
0x003AEC02, 0x003B2006, 0x003C041F, 0x003CD00C, 0x003DC417,
0x003E340B, 0x003E6424, 0x003EF80F, 0x003F380D, 0x0040AC14,
0x00412806, 0x00415804, 0x00417803, 0x00418803, 0x00419C07,
0x0041C404, 0x0042080C, 0x00423C01, 0x00426806, 0x0043EC01,
0x004D740C, 0x004E400A, 0x00500001, 0x0059B402, 0x005A0001,
0x005A6C02, 0x005BAC03, 0x005C4803, 0x005CC805, 0x005D4802,
0x005DC802, 0x005ED023, 0x005F6004, 0x005F7401, 0x0060000F,
0x0062A401, 0x0064800C, 0x0064C00C, 0x00650001, 0x00651002,
0x0066C011, 0x00672002, 0x00677822, 0x00685C05, 0x00687802,
0x0069540A, 0x0069801D, 0x0069FC01, 0x006A8007, 0x006AA006,
0x006C0005, 0x006CD011, 0x006D6823, 0x006E0003, 0x006E840D,
0x006F980E, 0x006FF004, 0x00709014, 0x0070EC05, 0x0071F802,
0x00730008, 0x00734019, 0x0073B401, 0x0073C803, 0x00770027,
0x0077F004, 0x007EF401, 0x007EFC03, 0x007F3403, 0x007F7403,
0x007FB403, 0x007FF402, 0x00800065, 0x0081A806, 0x0081E805,
0x00822805, 0x0082801A, 0x00834021, 0x00840002, 0x00840C04,
0x00842002, 0x00845001, 0x00845803, 0x00847806, 0x00849401,
0x00849C01, 0x0084A401, 0x0084B801, 0x0084E802, 0x00850005,
0x00852804, 0x00853C01, 0x00864264, 0x00900027, 0x0091000B,
0x0092704E, 0x00940200, 0x009C0475, 0x009E53B9, 0x00AD400A,
0x00B39406, 0x00B3BC03, 0x00B3E404, 0x00B3F802, 0x00B5C001,
0x00B5FC01, 0x00B7804F, 0x00B8C00C, 0x00BA001A, 0x00BA6C59,
0x00BC00D6, 0x00BFC00C, 0x00C00005, 0x00C02019, 0x00C0A807,
0x00C0D802, 0x00C0F403, 0x00C26404, 0x00C28001, 0x00C3EC01,
0x00C64002, 0x00C6580A, 0x00C70024, 0x00C8001F, 0x00C8A81E,
0x00C94001, 0x00C98020, 0x00CA2827, 0x00CB003F, 0x00CC0100,
0x01370040, 0x02924037, 0x0293F802, 0x02983403, 0x0299BC10,
0x029A7C01, 0x029BC008, 0x029C0017, 0x029C8002, 0x029E2402,
0x02A00801, 0x02A01801, 0x02A02C01, 0x02A08C09, 0x02A0D804,
0x02A1D004, 0x02A20002, 0x02A2D011, 0x02A33802, 0x02A38012,
0x02A3E003, 0x02A4980A, 0x02A51C0D, 0x02A57C01, 0x02A60004,
0x02A6CC1B, 0x02A77802, 0x02A8A40E, 0x02A90C01, 0x02A93002,
0x02A97004, 0x02A9DC03, 0x02A9EC01, 0x02AAC001, 0x02AAC803,
0x02AADC02, 0x02AAF802, 0x02AB0401, 0x02AB7802, 0x02ABAC07,
0x02ABD402, 0x02AF8C0B, 0x03600001, 0x036DFC02, 0x036FFC02,
0x037FFC01, 0x03EC7801, 0x03ECA401, 0x03EEC810, 0x03F4F802,
0x03F7F002, 0x03F8001A, 0x03F88007, 0x03F8C023, 0x03F95013,
0x03F9A004, 0x03FBFC01, 0x03FC040F, 0x03FC6807, 0x03FCEC06,
0x03FD6C0B, 0x03FF8007, 0x03FFA007, 0x03FFE405, 0x04040003,
0x0404DC09, 0x0405E411, 0x0406400C, 0x0407402E, 0x040E7C01,
0x040F4001, 0x04215C01, 0x04247C01, 0x0424FC01, 0x04280403,
0x04281402, 0x04283004, 0x0428E003, 0x0428FC01, 0x04294009,
0x0429FC01, 0x042CE407, 0x04400003, 0x0440E016, 0x04420003,
0x0442C012, 0x04440003, 0x04449C0E, 0x04450004, 0x04460003,
0x0446CC0E, 0x04471404, 0x045AAC0D, 0x0491C004, 0x05BD442E,
0x05BE3C04, 0x074000F6, 0x07440027, 0x0744A4B5, 0x07480046,
0x074C0057, 0x075B0401, 0x075B6C01, 0x075BEC01, 0x075C5401,
0x075CD401, 0x075D3C01, 0x075DBC01, 0x075E2401, 0x075EA401,
0x075F0C01, 0x07BBC002, 0x07C0002C, 0x07C0C064, 0x07C2800F,
0x07C2C40E, 0x07C3040F, 0x07C3440F, 0x07C4401F, 0x07C4C03C,
0x07C5C02B, 0x07C7981D, 0x07C8402B, 0x07C90009, 0x07C94002,
0x07CC0021, 0x07CCC006, 0x07CCDC46, 0x07CE0014, 0x07CE8025,
0x07CF1805, 0x07CF8011, 0x07D0003F, 0x07D10001, 0x07D108B6,
0x07D3E404, 0x07D4003E, 0x07D50004, 0x07D54018, 0x07D7EC46,
0x07D9140B, 0x07DA0046, 0x07DC0074, 0x38000401, 0x38008060,
0x380400F0,
};
static const unsigned int aAscii[4] = {
0xFFFFFFFF, 0xFC00FFFF, 0xF8000001, 0xF8000001,
};
if( (unsigned int)c<128 ){
return ( (aAscii[c >> 5] & (1 << (c & 0x001F)))==0 );
}else if( (unsigned int)c<(1<<22) ){
unsigned int key = (((unsigned int)c)<<10) | 0x000003FF;
int iRes = 0;
int iHi = sizeof(aEntry)/sizeof(aEntry[0]) - 1;
int iLo = 0;
while( iHi>=iLo ){
int iTest = (iHi + iLo) / 2;
if( key >= aEntry[iTest] ){
iRes = iTest;
iLo = iTest+1;
}else{
iHi = iTest-1;
}
}
assert( aEntry[0]<key );
assert( key>=aEntry[iRes] );
return (((unsigned int)c) >= ((aEntry[iRes]>>10) + (aEntry[iRes]&0x3FF)));
}
return 1;
}
/*
@@ -358,3 +229,536 @@ int sqlite3Fts5UnicodeFold(int c, int bRemoveDiacritic){
return ret;
}
#if 0
int sqlite3Fts5UnicodeNCat(void) {
return 32;
}
#endif
int sqlite3Fts5UnicodeCatParse(const char *zCat, u8 *aArray){
aArray[0] = 1;
switch( zCat[0] ){
case 'C':
switch( zCat[1] ){
case 'c': aArray[1] = 1; break;
case 'f': aArray[2] = 1; break;
case 'n': aArray[3] = 1; break;
case 's': aArray[4] = 1; break;
case 'o': aArray[31] = 1; break;
case '*':
aArray[1] = 1;
aArray[2] = 1;
aArray[3] = 1;
aArray[4] = 1;
aArray[31] = 1;
break;
default: return 1; }
break;
case 'L':
switch( zCat[1] ){
case 'l': aArray[5] = 1; break;
case 'm': aArray[6] = 1; break;
case 'o': aArray[7] = 1; break;
case 't': aArray[8] = 1; break;
case 'u': aArray[9] = 1; break;
case 'C': aArray[30] = 1; break;
case '*':
aArray[5] = 1;
aArray[6] = 1;
aArray[7] = 1;
aArray[8] = 1;
aArray[9] = 1;
aArray[30] = 1;
break;
default: return 1; }
break;
case 'M':
switch( zCat[1] ){
case 'c': aArray[10] = 1; break;
case 'e': aArray[11] = 1; break;
case 'n': aArray[12] = 1; break;
case '*':
aArray[10] = 1;
aArray[11] = 1;
aArray[12] = 1;
break;
default: return 1; }
break;
case 'N':
switch( zCat[1] ){
case 'd': aArray[13] = 1; break;
case 'l': aArray[14] = 1; break;
case 'o': aArray[15] = 1; break;
case '*':
aArray[13] = 1;
aArray[14] = 1;
aArray[15] = 1;
break;
default: return 1; }
break;
case 'P':
switch( zCat[1] ){
case 'c': aArray[16] = 1; break;
case 'd': aArray[17] = 1; break;
case 'e': aArray[18] = 1; break;
case 'f': aArray[19] = 1; break;
case 'i': aArray[20] = 1; break;
case 'o': aArray[21] = 1; break;
case 's': aArray[22] = 1; break;
case '*':
aArray[16] = 1;
aArray[17] = 1;
aArray[18] = 1;
aArray[19] = 1;
aArray[20] = 1;
aArray[21] = 1;
aArray[22] = 1;
break;
default: return 1; }
break;
case 'S':
switch( zCat[1] ){
case 'c': aArray[23] = 1; break;
case 'k': aArray[24] = 1; break;
case 'm': aArray[25] = 1; break;
case 'o': aArray[26] = 1; break;
case '*':
aArray[23] = 1;
aArray[24] = 1;
aArray[25] = 1;
aArray[26] = 1;
break;
default: return 1; }
break;
case 'Z':
switch( zCat[1] ){
case 'l': aArray[27] = 1; break;
case 'p': aArray[28] = 1; break;
case 's': aArray[29] = 1; break;
case '*':
aArray[27] = 1;
aArray[28] = 1;
aArray[29] = 1;
break;
default: return 1; }
break;
}
return 0;
}
static u16 aFts5UnicodeBlock[] = {
0, 1471, 1753, 1760, 1760, 1760, 1760, 1760, 1760, 1760,
1760, 1760, 1760, 1760, 1760, 1763, 1765,
};
static u16 aFts5UnicodeMap[] = {
0, 32, 33, 36, 37, 40, 41, 42, 43, 44,
45, 46, 48, 58, 60, 63, 65, 91, 92, 93,
94, 95, 96, 97, 123, 124, 125, 126, 127, 160,
161, 162, 166, 167, 168, 169, 170, 171, 172, 173,
174, 175, 176, 177, 178, 180, 181, 182, 184, 185,
186, 187, 188, 191, 192, 215, 216, 223, 247, 248,
256, 312, 313, 329, 330, 377, 383, 385, 387, 388,
391, 394, 396, 398, 402, 403, 405, 406, 409, 412,
414, 415, 417, 418, 423, 427, 428, 431, 434, 436,
437, 440, 442, 443, 444, 446, 448, 452, 453, 454,
455, 456, 457, 458, 459, 460, 461, 477, 478, 496,
497, 498, 499, 500, 503, 505, 506, 564, 570, 572,
573, 575, 577, 580, 583, 584, 592, 660, 661, 688,
706, 710, 722, 736, 741, 748, 749, 750, 751, 768,
880, 884, 885, 886, 890, 891, 894, 900, 902, 903,
904, 908, 910, 912, 913, 931, 940, 975, 977, 978,
981, 984, 1008, 1012, 1014, 1015, 1018, 1020, 1021, 1072,
1120, 1154, 1155, 1160, 1162, 1217, 1231, 1232, 1329, 1369,
1370, 1377, 1417, 1418, 1423, 1425, 1470, 1471, 1472, 1473,
1475, 1476, 1478, 1479, 1488, 1520, 1523, 1536, 1542, 1545,
1547, 1548, 1550, 1552, 1563, 1566, 1568, 1600, 1601, 1611,
1632, 1642, 1646, 1648, 1649, 1748, 1749, 1750, 1757, 1758,
1759, 1765, 1767, 1769, 1770, 1774, 1776, 1786, 1789, 1791,
1792, 1807, 1808, 1809, 1810, 1840, 1869, 1958, 1969, 1984,
1994, 2027, 2036, 2038, 2039, 2042, 2048, 2070, 2074, 2075,
2084, 2085, 2088, 2089, 2096, 2112, 2137, 2142, 2208, 2210,
2276, 2304, 2307, 2308, 2362, 2363, 2364, 2365, 2366, 2369,
2377, 2381, 2382, 2384, 2385, 2392, 2402, 2404, 2406, 2416,
2417, 2418, 2425, 2433, 2434, 2437, 2447, 2451, 2474, 2482,
2486, 2492, 2493, 2494, 2497, 2503, 2507, 2509, 2510, 2519,
2524, 2527, 2530, 2534, 2544, 2546, 2548, 2554, 2555, 2561,
2563, 2565, 2575, 2579, 2602, 2610, 2613, 2616, 2620, 2622,
2625, 2631, 2635, 2641, 2649, 2654, 2662, 2672, 2674, 2677,
2689, 2691, 2693, 2703, 2707, 2730, 2738, 2741, 2748, 2749,
2750, 2753, 2759, 2761, 2763, 2765, 2768, 2784, 2786, 2790,
2800, 2801, 2817, 2818, 2821, 2831, 2835, 2858, 2866, 2869,
2876, 2877, 2878, 2879, 2880, 2881, 2887, 2891, 2893, 2902,
2903, 2908, 2911, 2914, 2918, 2928, 2929, 2930, 2946, 2947,
2949, 2958, 2962, 2969, 2972, 2974, 2979, 2984, 2990, 3006,
3008, 3009, 3014, 3018, 3021, 3024, 3031, 3046, 3056, 3059,
3065, 3066, 3073, 3077, 3086, 3090, 3114, 3125, 3133, 3134,
3137, 3142, 3146, 3157, 3160, 3168, 3170, 3174, 3192, 3199,
3202, 3205, 3214, 3218, 3242, 3253, 3260, 3261, 3262, 3263,
3264, 3270, 3271, 3274, 3276, 3285, 3294, 3296, 3298, 3302,
3313, 3330, 3333, 3342, 3346, 3389, 3390, 3393, 3398, 3402,
3405, 3406, 3415, 3424, 3426, 3430, 3440, 3449, 3450, 3458,
3461, 3482, 3507, 3517, 3520, 3530, 3535, 3538, 3542, 3544,
3570, 3572, 3585, 3633, 3634, 3636, 3647, 3648, 3654, 3655,
3663, 3664, 3674, 3713, 3716, 3719, 3722, 3725, 3732, 3737,
3745, 3749, 3751, 3754, 3757, 3761, 3762, 3764, 3771, 3773,
3776, 3782, 3784, 3792, 3804, 3840, 3841, 3844, 3859, 3860,
3861, 3864, 3866, 3872, 3882, 3892, 3893, 3894, 3895, 3896,
3897, 3898, 3899, 3900, 3901, 3902, 3904, 3913, 3953, 3967,
3968, 3973, 3974, 3976, 3981, 3993, 4030, 4038, 4039, 4046,
4048, 4053, 4057, 4096, 4139, 4141, 4145, 4146, 4152, 4153,
4155, 4157, 4159, 4160, 4170, 4176, 4182, 4184, 4186, 4190,
4193, 4194, 4197, 4199, 4206, 4209, 4213, 4226, 4227, 4229,
4231, 4237, 4238, 4239, 4240, 4250, 4253, 4254, 4256, 4295,
4301, 4304, 4347, 4348, 4349, 4682, 4688, 4696, 4698, 4704,
4746, 4752, 4786, 4792, 4800, 4802, 4808, 4824, 4882, 4888,
4957, 4960, 4969, 4992, 5008, 5024, 5120, 5121, 5741, 5743,
5760, 5761, 5787, 5788, 5792, 5867, 5870, 5888, 5902, 5906,
5920, 5938, 5941, 5952, 5970, 5984, 5998, 6002, 6016, 6068,
6070, 6071, 6078, 6086, 6087, 6089, 6100, 6103, 6104, 6107,
6108, 6109, 6112, 6128, 6144, 6150, 6151, 6155, 6158, 6160,
6176, 6211, 6212, 6272, 6313, 6314, 6320, 6400, 6432, 6435,
6439, 6441, 6448, 6450, 6451, 6457, 6464, 6468, 6470, 6480,
6512, 6528, 6576, 6593, 6600, 6608, 6618, 6622, 6656, 6679,
6681, 6686, 6688, 6741, 6742, 6743, 6744, 6752, 6753, 6754,
6755, 6757, 6765, 6771, 6783, 6784, 6800, 6816, 6823, 6824,
6912, 6916, 6917, 6964, 6965, 6966, 6971, 6972, 6973, 6978,
6979, 6981, 6992, 7002, 7009, 7019, 7028, 7040, 7042, 7043,
7073, 7074, 7078, 7080, 7082, 7083, 7084, 7086, 7088, 7098,
7142, 7143, 7144, 7146, 7149, 7150, 7151, 7154, 7164, 7168,
7204, 7212, 7220, 7222, 7227, 7232, 7245, 7248, 7258, 7288,
7294, 7360, 7376, 7379, 7380, 7393, 7394, 7401, 7405, 7406,
7410, 7412, 7413, 7424, 7468, 7531, 7544, 7545, 7579, 7616,
7676, 7680, 7830, 7838, 7936, 7944, 7952, 7960, 7968, 7976,
7984, 7992, 8000, 8008, 8016, 8025, 8027, 8029, 8031, 8033,
8040, 8048, 8064, 8072, 8080, 8088, 8096, 8104, 8112, 8118,
8120, 8124, 8125, 8126, 8127, 8130, 8134, 8136, 8140, 8141,
8144, 8150, 8152, 8157, 8160, 8168, 8173, 8178, 8182, 8184,
8188, 8189, 8192, 8203, 8208, 8214, 8216, 8217, 8218, 8219,
8221, 8222, 8223, 8224, 8232, 8233, 8234, 8239, 8240, 8249,
8250, 8251, 8255, 8257, 8260, 8261, 8262, 8263, 8274, 8275,
8276, 8277, 8287, 8288, 8298, 8304, 8305, 8308, 8314, 8317,
8318, 8319, 8320, 8330, 8333, 8334, 8336, 8352, 8400, 8413,
8417, 8418, 8421, 8448, 8450, 8451, 8455, 8456, 8458, 8459,
8462, 8464, 8467, 8468, 8469, 8470, 8472, 8473, 8478, 8484,
8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8496, 8500,
8501, 8505, 8506, 8508, 8510, 8512, 8517, 8519, 8522, 8523,
8524, 8526, 8527, 8528, 8544, 8579, 8581, 8585, 8592, 8597,
8602, 8604, 8608, 8609, 8611, 8612, 8614, 8615, 8622, 8623,
8654, 8656, 8658, 8659, 8660, 8661, 8692, 8960, 8968, 8972,
8992, 8994, 9001, 9002, 9003, 9084, 9085, 9115, 9140, 9180,
9186, 9216, 9280, 9312, 9372, 9450, 9472, 9655, 9656, 9665,
9666, 9720, 9728, 9839, 9840, 9985, 10088, 10089, 10090, 10091,
10092, 10093, 10094, 10095, 10096, 10097, 10098, 10099, 10100, 10101,
10102, 10132, 10176, 10181, 10182, 10183, 10214, 10215, 10216, 10217,
10218, 10219, 10220, 10221, 10222, 10223, 10224, 10240, 10496, 10627,
10628, 10629, 10630, 10631, 10632, 10633, 10634, 10635, 10636, 10637,
10638, 10639, 10640, 10641, 10642, 10643, 10644, 10645, 10646, 10647,
10648, 10649, 10712, 10713, 10714, 10715, 10716, 10748, 10749, 10750,
11008, 11056, 11077, 11079, 11088, 11264, 11312, 11360, 11363, 11365,
11367, 11374, 11377, 11378, 11380, 11381, 11383, 11388, 11390, 11393,
11394, 11492, 11493, 11499, 11503, 11506, 11513, 11517, 11518, 11520,
11559, 11565, 11568, 11631, 11632, 11647, 11648, 11680, 11688, 11696,
11704, 11712, 11720, 11728, 11736, 11744, 11776, 11778, 11779, 11780,
11781, 11782, 11785, 11786, 11787, 11788, 11789, 11790, 11799, 11800,
11802, 11803, 11804, 11805, 11806, 11808, 11809, 11810, 11811, 11812,
11813, 11814, 11815, 11816, 11817, 11818, 11823, 11824, 11834, 11904,
11931, 12032, 12272, 12288, 12289, 12292, 12293, 12294, 12295, 12296,
12297, 12298, 12299, 12300, 12301, 12302, 12303, 12304, 12305, 12306,
12308, 12309, 12310, 12311, 12312, 12313, 12314, 12315, 12316, 12317,
12318, 12320, 12321, 12330, 12334, 12336, 12337, 12342, 12344, 12347,
12348, 12349, 12350, 12353, 12441, 12443, 12445, 12447, 12448, 12449,
12539, 12540, 12543, 12549, 12593, 12688, 12690, 12694, 12704, 12736,
12784, 12800, 12832, 12842, 12872, 12880, 12881, 12896, 12928, 12938,
12977, 12992, 13056, 13312, 19893, 19904, 19968, 40908, 40960, 40981,
40982, 42128, 42192, 42232, 42238, 42240, 42508, 42509, 42512, 42528,
42538, 42560, 42606, 42607, 42608, 42611, 42612, 42622, 42623, 42624,
42655, 42656, 42726, 42736, 42738, 42752, 42775, 42784, 42786, 42800,
42802, 42864, 42865, 42873, 42878, 42888, 42889, 42891, 42896, 42912,
43000, 43002, 43003, 43010, 43011, 43014, 43015, 43019, 43020, 43043,
43045, 43047, 43048, 43056, 43062, 43064, 43065, 43072, 43124, 43136,
43138, 43188, 43204, 43214, 43216, 43232, 43250, 43256, 43259, 43264,
43274, 43302, 43310, 43312, 43335, 43346, 43359, 43360, 43392, 43395,
43396, 43443, 43444, 43446, 43450, 43452, 43453, 43457, 43471, 43472,
43486, 43520, 43561, 43567, 43569, 43571, 43573, 43584, 43587, 43588,
43596, 43597, 43600, 43612, 43616, 43632, 43633, 43639, 43642, 43643,
43648, 43696, 43697, 43698, 43701, 43703, 43705, 43710, 43712, 43713,
43714, 43739, 43741, 43742, 43744, 43755, 43756, 43758, 43760, 43762,
43763, 43765, 43766, 43777, 43785, 43793, 43808, 43816, 43968, 44003,
44005, 44006, 44008, 44009, 44011, 44012, 44013, 44016, 44032, 55203,
55216, 55243, 55296, 56191, 56319, 57343, 57344, 63743, 63744, 64112,
64256, 64275, 64285, 64286, 64287, 64297, 64298, 64312, 64318, 64320,
64323, 64326, 64434, 64467, 64830, 64831, 64848, 64914, 65008, 65020,
65021, 65024, 65040, 65047, 65048, 65049, 65056, 65072, 65073, 65075,
65077, 65078, 65079, 65080, 65081, 65082, 65083, 65084, 65085, 65086,
65087, 65088, 65089, 65090, 65091, 65092, 65093, 65095, 65096, 65097,
65101, 65104, 65108, 65112, 65113, 65114, 65115, 65116, 65117, 65118,
65119, 65122, 65123, 65124, 65128, 65129, 65130, 65136, 65142, 65279,
65281, 65284, 65285, 65288, 65289, 65290, 65291, 65292, 65293, 65294,
65296, 65306, 65308, 65311, 65313, 65339, 65340, 65341, 65342, 65343,
65344, 65345, 65371, 65372, 65373, 65374, 65375, 65376, 65377, 65378,
65379, 65380, 65382, 65392, 65393, 65438, 65440, 65474, 65482, 65490,
65498, 65504, 65506, 65507, 65508, 65509, 65512, 65513, 65517, 65529,
65532, 0, 13, 40, 60, 63, 80, 128, 256, 263,
311, 320, 373, 377, 394, 400, 464, 509, 640, 672,
768, 800, 816, 833, 834, 842, 896, 927, 928, 968,
976, 977, 1024, 1064, 1104, 1184, 2048, 2056, 2058, 2103,
2108, 2111, 2135, 2136, 2304, 2326, 2335, 2336, 2367, 2432,
2494, 2560, 2561, 2565, 2572, 2576, 2581, 2585, 2616, 2623,
2624, 2640, 2656, 2685, 2687, 2816, 2873, 2880, 2904, 2912,
2936, 3072, 3680, 4096, 4097, 4098, 4099, 4152, 4167, 4178,
4198, 4224, 4226, 4227, 4272, 4275, 4279, 4281, 4283, 4285,
4286, 4304, 4336, 4352, 4355, 4391, 4396, 4397, 4406, 4416,
4480, 4482, 4483, 4531, 4534, 4543, 4545, 4549, 4560, 5760,
5803, 5804, 5805, 5806, 5808, 5814, 5815, 5824, 8192, 9216,
9328, 12288, 26624, 28416, 28496, 28497, 28559, 28563, 45056, 53248,
53504, 53545, 53605, 53607, 53610, 53613, 53619, 53627, 53635, 53637,
53644, 53674, 53678, 53760, 53826, 53829, 54016, 54112, 54272, 54298,
54324, 54350, 54358, 54376, 54402, 54428, 54430, 54434, 54437, 54441,
54446, 54454, 54459, 54461, 54469, 54480, 54506, 54532, 54535, 54541,
54550, 54558, 54584, 54587, 54592, 54598, 54602, 54610, 54636, 54662,
54688, 54714, 54740, 54766, 54792, 54818, 54844, 54870, 54896, 54922,
54952, 54977, 54978, 55003, 55004, 55010, 55035, 55036, 55061, 55062,
55068, 55093, 55094, 55119, 55120, 55126, 55151, 55152, 55177, 55178,
55184, 55209, 55210, 55235, 55236, 55242, 55246, 60928, 60933, 60961,
60964, 60967, 60969, 60980, 60985, 60987, 60994, 60999, 61001, 61003,
61005, 61009, 61012, 61015, 61017, 61019, 61021, 61023, 61025, 61028,
61031, 61036, 61044, 61049, 61054, 61056, 61067, 61089, 61093, 61099,
61168, 61440, 61488, 61600, 61617, 61633, 61649, 61696, 61712, 61744,
61808, 61926, 61968, 62016, 62032, 62208, 62256, 62263, 62336, 62368,
62406, 62432, 62464, 62528, 62530, 62713, 62720, 62784, 62800, 62971,
63045, 63104, 63232, 0, 42710, 42752, 46900, 46912, 47133, 63488,
1, 32, 256, 0, 65533,
};
static u16 aFts5UnicodeData[] = {
1025, 61, 117, 55, 117, 54, 50, 53, 57, 53,
49, 85, 333, 85, 121, 85, 841, 54, 53, 50,
56, 48, 56, 837, 54, 57, 50, 57, 1057, 61,
53, 151, 58, 53, 56, 58, 39, 52, 57, 34,
58, 56, 58, 57, 79, 56, 37, 85, 56, 47,
39, 51, 111, 53, 745, 57, 233, 773, 57, 261,
1822, 37, 542, 37, 1534, 222, 69, 73, 37, 126,
126, 73, 69, 137, 37, 73, 37, 105, 101, 73,
37, 73, 37, 190, 158, 37, 126, 126, 73, 37,
126, 94, 37, 39, 94, 69, 135, 41, 40, 37,
41, 40, 37, 41, 40, 37, 542, 37, 606, 37,
41, 40, 37, 126, 73, 37, 1886, 197, 73, 37,
73, 69, 126, 105, 37, 286, 2181, 39, 869, 582,
152, 390, 472, 166, 248, 38, 56, 38, 568, 3596,
158, 38, 56, 94, 38, 101, 53, 88, 41, 53,
105, 41, 73, 37, 553, 297, 1125, 94, 37, 105,
101, 798, 133, 94, 57, 126, 94, 37, 1641, 1541,
1118, 58, 172, 75, 1790, 478, 37, 2846, 1225, 38,
213, 1253, 53, 49, 55, 1452, 49, 44, 53, 76,
53, 76, 53, 44, 871, 103, 85, 162, 121, 85,
55, 85, 90, 364, 53, 85, 1031, 38, 327, 684,
333, 149, 71, 44, 3175, 53, 39, 236, 34, 58,
204, 70, 76, 58, 140, 71, 333, 103, 90, 39,
469, 34, 39, 44, 967, 876, 2855, 364, 39, 333,
1063, 300, 70, 58, 117, 38, 711, 140, 38, 300,
38, 108, 38, 172, 501, 807, 108, 53, 39, 359,
876, 108, 42, 1735, 44, 42, 44, 39, 106, 268,
138, 44, 74, 39, 236, 327, 76, 85, 333, 53,
38, 199, 231, 44, 74, 263, 71, 711, 231, 39,
135, 44, 39, 106, 140, 74, 74, 44, 39, 42,
71, 103, 76, 333, 71, 87, 207, 58, 55, 76,
42, 199, 71, 711, 231, 71, 71, 71, 44, 106,
76, 76, 108, 44, 135, 39, 333, 76, 103, 44,
76, 42, 295, 103, 711, 231, 71, 167, 44, 39,
106, 172, 76, 42, 74, 44, 39, 71, 76, 333,
53, 55, 44, 74, 263, 71, 711, 231, 71, 167,
44, 39, 42, 44, 42, 140, 74, 74, 44, 44,
42, 71, 103, 76, 333, 58, 39, 207, 44, 39,
199, 103, 135, 71, 39, 71, 71, 103, 391, 74,
44, 74, 106, 106, 44, 39, 42, 333, 111, 218,
55, 58, 106, 263, 103, 743, 327, 167, 39, 108,
138, 108, 140, 76, 71, 71, 76, 333, 239, 58,
74, 263, 103, 743, 327, 167, 44, 39, 42, 44,
170, 44, 74, 74, 76, 74, 39, 71, 76, 333,
71, 74, 263, 103, 1319, 39, 106, 140, 106, 106,
44, 39, 42, 71, 76, 333, 207, 58, 199, 74,
583, 775, 295, 39, 231, 44, 106, 108, 44, 266,
74, 53, 1543, 44, 71, 236, 55, 199, 38, 268,
53, 333, 85, 71, 39, 71, 39, 39, 135, 231,
103, 39, 39, 71, 135, 44, 71, 204, 76, 39,
167, 38, 204, 333, 135, 39, 122, 501, 58, 53,
122, 76, 218, 333, 335, 58, 44, 58, 44, 58,
44, 54, 50, 54, 50, 74, 263, 1159, 460, 42,
172, 53, 76, 167, 364, 1164, 282, 44, 218, 90,
181, 154, 85, 1383, 74, 140, 42, 204, 42, 76,
74, 76, 39, 333, 213, 199, 74, 76, 135, 108,
39, 106, 71, 234, 103, 140, 423, 44, 74, 76,
202, 44, 39, 42, 333, 106, 44, 90, 1225, 41,
41, 1383, 53, 38, 10631, 135, 231, 39, 135, 1319,
135, 1063, 135, 231, 39, 135, 487, 1831, 135, 2151,
108, 309, 655, 519, 346, 2727, 49, 19847, 85, 551,
61, 839, 54, 50, 2407, 117, 110, 423, 135, 108,
583, 108, 85, 583, 76, 423, 103, 76, 1671, 76,
42, 236, 266, 44, 74, 364, 117, 38, 117, 55,
39, 44, 333, 335, 213, 49, 149, 108, 61, 333,
1127, 38, 1671, 1319, 44, 39, 2247, 935, 108, 138,
76, 106, 74, 44, 202, 108, 58, 85, 333, 967,
167, 1415, 554, 231, 74, 333, 47, 1114, 743, 76,
106, 85, 1703, 42, 44, 42, 236, 44, 42, 44,
74, 268, 202, 332, 44, 333, 333, 245, 38, 213,
140, 42, 1511, 44, 42, 172, 42, 44, 170, 44,
74, 231, 333, 245, 346, 300, 314, 76, 42, 967,
42, 140, 74, 76, 42, 44, 74, 71, 333, 1415,
44, 42, 76, 106, 44, 42, 108, 74, 149, 1159,
266, 268, 74, 76, 181, 333, 103, 333, 967, 198,
85, 277, 108, 53, 428, 42, 236, 135, 44, 135,
74, 44, 71, 1413, 2022, 421, 38, 1093, 1190, 1260,
140, 4830, 261, 3166, 261, 265, 197, 201, 261, 265,
261, 265, 197, 201, 261, 41, 41, 41, 94, 229,
265, 453, 261, 264, 261, 264, 261, 264, 165, 69,
137, 40, 56, 37, 120, 101, 69, 137, 40, 120,
133, 69, 137, 120, 261, 169, 120, 101, 69, 137,
40, 88, 381, 162, 209, 85, 52, 51, 54, 84,
51, 54, 52, 277, 59, 60, 162, 61, 309, 52,
51, 149, 80, 117, 57, 54, 50, 373, 57, 53,
48, 341, 61, 162, 194, 47, 38, 207, 121, 54,
50, 38, 335, 121, 54, 50, 422, 855, 428, 139,
44, 107, 396, 90, 41, 154, 41, 90, 37, 105,
69, 105, 37, 58, 41, 90, 57, 169, 218, 41,
58, 41, 58, 41, 58, 137, 58, 37, 137, 37,
135, 37, 90, 69, 73, 185, 94, 101, 58, 57,
90, 37, 58, 527, 1134, 94, 142, 47, 185, 186,
89, 154, 57, 90, 57, 90, 57, 250, 57, 1018,
89, 90, 57, 58, 57, 1018, 8601, 282, 153, 666,
89, 250, 54, 50, 2618, 57, 986, 825, 1306, 217,
602, 1274, 378, 1935, 2522, 719, 5882, 57, 314, 57,
1754, 281, 3578, 57, 4634, 3322, 54, 50, 54, 50,
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
975, 1434, 185, 54, 50, 1017, 54, 50, 54, 50,
54, 50, 54, 50, 54, 50, 537, 8218, 4217, 54,
50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
50, 54, 50, 54, 50, 54, 50, 54, 50, 54,
50, 2041, 54, 50, 54, 50, 1049, 54, 50, 8281,
1562, 697, 90, 217, 346, 1513, 1509, 126, 73, 69,
254, 105, 37, 94, 37, 94, 165, 70, 105, 37,
3166, 37, 218, 158, 108, 94, 149, 47, 85, 1221,
37, 37, 1799, 38, 53, 44, 743, 231, 231, 231,
231, 231, 231, 231, 231, 1036, 85, 52, 51, 52,
51, 117, 52, 51, 53, 52, 51, 309, 49, 85,
49, 53, 52, 51, 85, 52, 51, 54, 50, 54,
50, 54, 50, 54, 50, 181, 38, 341, 81, 858,
2874, 6874, 410, 61, 117, 58, 38, 39, 46, 54,
50, 54, 50, 54, 50, 54, 50, 54, 50, 90,
54, 50, 54, 50, 54, 50, 54, 50, 49, 54,
82, 58, 302, 140, 74, 49, 166, 90, 110, 38,
39, 53, 90, 2759, 76, 88, 70, 39, 49, 2887,
53, 102, 39, 1319, 3015, 90, 143, 346, 871, 1178,
519, 1018, 335, 986, 271, 58, 495, 1050, 335, 1274,
495, 2042, 8218, 39, 39, 2074, 39, 39, 679, 38,
36583, 1786, 1287, 198, 85, 8583, 38, 117, 519, 333,
71, 1502, 39, 44, 107, 53, 332, 53, 38, 798,
44, 2247, 334, 76, 213, 760, 294, 88, 478, 69,
2014, 38, 261, 190, 350, 38, 88, 158, 158, 382,
70, 37, 231, 44, 103, 44, 135, 44, 743, 74,
76, 42, 154, 207, 90, 55, 58, 1671, 149, 74,
1607, 522, 44, 85, 333, 588, 199, 117, 39, 333,
903, 268, 85, 743, 364, 74, 53, 935, 108, 42,
1511, 44, 74, 140, 74, 44, 138, 437, 38, 333,
85, 1319, 204, 74, 76, 74, 76, 103, 44, 263,
44, 42, 333, 149, 519, 38, 199, 122, 39, 42,
1543, 44, 39, 108, 71, 76, 167, 76, 39, 44,
39, 71, 38, 85, 359, 42, 76, 74, 85, 39,
70, 42, 44, 199, 199, 199, 231, 231, 1127, 74,
44, 74, 44, 74, 53, 42, 44, 333, 39, 39,
743, 1575, 36, 68, 68, 36, 63, 63, 11719, 3399,
229, 165, 39, 44, 327, 57, 423, 167, 39, 71,
71, 3463, 536, 11623, 54, 50, 2055, 1735, 391, 55,
58, 524, 245, 54, 50, 53, 236, 53, 81, 80,
54, 50, 54, 50, 54, 50, 54, 50, 54, 50,
54, 50, 54, 50, 54, 50, 85, 54, 50, 149,
112, 117, 149, 49, 54, 50, 54, 50, 54, 50,
117, 57, 49, 121, 53, 55, 85, 167, 4327, 34,
117, 55, 117, 54, 50, 53, 57, 53, 49, 85,
333, 85, 121, 85, 841, 54, 53, 50, 56, 48,
56, 837, 54, 57, 50, 57, 54, 50, 53, 54,
50, 85, 327, 38, 1447, 70, 999, 199, 199, 199,
103, 87, 57, 56, 58, 87, 58, 153, 90, 98,
90, 391, 839, 615, 71, 487, 455, 3943, 117, 1455,
314, 1710, 143, 570, 47, 410, 1466, 44, 935, 1575,
999, 143, 551, 46, 263, 46, 967, 53, 1159, 263,
53, 174, 1289, 1285, 2503, 333, 199, 39, 1415, 71,
39, 743, 53, 271, 711, 207, 53, 839, 53, 1799,
71, 39, 108, 76, 140, 135, 103, 871, 108, 44,
271, 309, 935, 79, 53, 1735, 245, 711, 271, 615,
271, 2343, 1007, 42, 44, 42, 1703, 492, 245, 655,
333, 76, 42, 1447, 106, 140, 74, 76, 85, 34,
149, 807, 333, 108, 1159, 172, 42, 268, 333, 149,
76, 42, 1543, 106, 300, 74, 135, 149, 333, 1383,
44, 42, 44, 74, 204, 42, 44, 333, 28135, 3182,
149, 34279, 18215, 2215, 39, 1482, 140, 422, 71, 7898,
1274, 1946, 74, 108, 122, 202, 258, 268, 90, 236,
986, 140, 1562, 2138, 108, 58, 2810, 591, 841, 837,
841, 229, 581, 841, 837, 41, 73, 41, 73, 137,
265, 133, 37, 229, 357, 841, 837, 73, 137, 265,
233, 837, 73, 137, 169, 41, 233, 837, 841, 837,
841, 837, 841, 837, 841, 837, 841, 837, 841, 901,
809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
809, 57, 805, 57, 197, 809, 57, 805, 57, 197,
809, 57, 805, 57, 197, 94, 1613, 135, 871, 71,
39, 39, 327, 135, 39, 39, 39, 39, 39, 39,
103, 71, 39, 39, 39, 39, 39, 39, 71, 39,
135, 231, 135, 135, 39, 327, 551, 103, 167, 551,
89, 1434, 3226, 506, 474, 506, 506, 367, 1018, 1946,
1402, 954, 1402, 314, 90, 1082, 218, 2266, 666, 1210,
186, 570, 2042, 58, 5850, 154, 2010, 154, 794, 2266,
378, 2266, 3738, 39, 39, 39, 39, 39, 39, 17351,
34, 3074, 7692, 63, 63,
};
int sqlite3Fts5UnicodeCategory(int iCode) {
int iRes = -1;
int iHi;
int iLo;
int ret;
u16 iKey;
if( iCode>=(1<<20) ){
return 0;
}
iLo = aFts5UnicodeBlock[(iCode>>16)];
iHi = aFts5UnicodeBlock[1+(iCode>>16)];
iKey = (iCode & 0xFFFF);
while( iHi>iLo ){
int iTest = (iHi + iLo) / 2;
assert( iTest>=iLo && iTest<iHi );
if( iKey>=aFts5UnicodeMap[iTest] ){
iRes = iTest;
iLo = iTest+1;
}else{
iHi = iTest;
}
}
if( iRes<0 ) return 0;
if( iKey>=(aFts5UnicodeMap[iRes]+(aFts5UnicodeData[iRes]>>5)) ) return 0;
ret = aFts5UnicodeData[iRes] & 0x1F;
if( ret!=30 ) return ret;
return ((iKey - aFts5UnicodeMap[iRes]) & 0x01) ? 5 : 9;
}
void sqlite3Fts5UnicodeAscii(u8 *aArray, u8 *aAscii){
int i = 0;
int iTbl = 0;
while( i<128 ){
int bToken = aArray[ aFts5UnicodeData[iTbl] & 0x1F ];
int n = (aFts5UnicodeData[iTbl] >> 5) + i;
for(; i<128 && i<n; i++){
aAscii[i] = bToken;
}
iTbl++;
}
}
+59
View File
@@ -0,0 +1,59 @@
# 2016 Jan 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5cat
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(x, tokenize="unicode61 categories 'L*'");
INSERT INTO t1 VALUES ('Unlike1option2values3and4column5names');
}
do_execsql_test 1.1 {
SELECT rowid FROM t1('option');
} {1}
do_execsql_test 1.2 {
CREATE VIRTUAL TABLE t2 USING fts5(x);
CREATE VIRTUAL TABLE t2t USING fts5vocab(t2, row);
CREATE VIRTUAL TABLE t3 USING fts5(
x, tokenize="unicode61 categories 'L* N* Co Mn'"
);
CREATE VIRTUAL TABLE t3t USING fts5vocab(t3, row);
CREATE VIRTUAL TABLE t4 USING fts5(
x, tokenize="unicode61 categories 'L* N* Co M*'"
);
CREATE VIRTUAL TABLE t4t USING fts5vocab(t4, row);
INSERT INTO t2 VALUES ('สนามกีฬา');
INSERT INTO t3 VALUES ('สนามกีฬา');
INSERT INTO t4 VALUES ('สนามกีฬา');
}
do_execsql_test 1.3 {
SELECT * FROM t2t
} {สนามก 1 1 ฬา 1 1}
do_execsql_test 1.4 {
SELECT * FROM t3t
} {สนามกีฬา 1 1}
do_execsql_test 1.5 {
SELECT * FROM t4t
} {สนามกีฬา 1 1}
finish_test
+4
View File
@@ -274,6 +274,7 @@ static void doDataTest1(
int rc = LSM_OK;
Datasource *pData;
TestDb *pDb;
int iToggle = 0;
/* Start the test case, open a database and allocate the datasource. */
pDb = testOpen(zSystem, 1, &rc);
@@ -287,8 +288,11 @@ static void doDataTest1(
testWriteDatasourceRange(pDb, pData, i, p->nVerify, &rc);
i += p->nVerify;
if( iToggle ) testBegin(pDb, 1, &rc);
/* Check that the db content is correct. */
testDbContents(pDb, pData, p->nRow, 0, i-1, p->nTest, p->bTestScan, &rc);
if( iToggle ) testCommit(pDb, 0, &rc);
iToggle = (iToggle+1)%2;
if( bRecover ){
testReopenRecover(&pDb, &rc);
+33 -6
View File
@@ -617,8 +617,12 @@ static int test_lsm_fetch(
if( pKey==0 ) return LSM_OK;
rc = lsm_csr_open(pDb->db, &csr);
if( rc!=LSM_OK ) return rc;
if( pDb->pCsr==0 ){
rc = lsm_csr_open(pDb->db, &csr);
if( rc!=LSM_OK ) return rc;
}else{
csr = pDb->pCsr;
}
rc = lsm_csr_seek(csr, pKey, nKey, LSM_SEEK_EQ);
if( rc==LSM_OK ){
@@ -638,7 +642,9 @@ static int test_lsm_fetch(
*pnVal = -1;
}
}
lsm_csr_close(csr);
if( pDb->pCsr==0 ){
lsm_csr_close(csr);
}
return rc;
}
@@ -652,10 +658,28 @@ static int test_lsm_scan(
){
LsmDb *pDb = (LsmDb *)pTestDb;
lsm_cursor *csr;
lsm_cursor *csr2 = 0;
int rc;
rc = lsm_csr_open(pDb->db, &csr);
if( rc!=LSM_OK ) return rc;
if( pDb->pCsr==0 ){
rc = lsm_csr_open(pDb->db, &csr);
if( rc!=LSM_OK ) return rc;
}else{
rc = LSM_OK;
csr = pDb->pCsr;
}
/* To enhance testing, if both pLast and pFirst are defined, seek the
** cursor to the "end" boundary here. Then the next block seeks it to
** the "start" ready for the scan. The point is to test that cursors
** can be reused. */
if( pLast && pFirst ){
if( bReverse ){
rc = lsm_csr_seek(csr, pFirst, nFirst, LSM_SEEK_LE);
}else{
rc = lsm_csr_seek(csr, pLast, nLast, LSM_SEEK_GE);
}
}
if( bReverse ){
if( pLast ){
@@ -696,7 +720,9 @@ static int test_lsm_scan(
}
}
lsm_csr_close(csr);
if( pDb->pCsr==0 ){
lsm_csr_close(csr);
}
return rc;
}
@@ -762,6 +788,7 @@ static void xWorkHook(lsm_db *db, void *pArg){
#define TEST_MT_MIN_CKPT -4
#define TEST_MT_MAX_CKPT -5
int test_lsm_config_str(
LsmDb *pLsm,
lsm_db *db,
+6 -1
View File
@@ -1922,6 +1922,7 @@ static int seekInLevel(
** is not a composite level and there is no split-key). Search the
** left-hand-side of the level in this case. */
if( res<0 ){
int i;
int iPtr = 0;
if( nRhs==0 ) iPtr = (int)*piPgno;
@@ -1931,12 +1932,16 @@ static int seekInLevel(
if( rc==LSM_OK && nRhs>0 && eSeek==LSM_SEEK_GE && aPtr[0].pPg==0 ){
res = 0;
}
for(i=1; i<=nRhs; i++){
segmentPtrReset(&aPtr[i], LSM_SEGMENTPTR_FREE_THRESHOLD);
}
}
if( res>=0 ){
int bHit = 0; /* True if at least one rhs is not EOF */
int iPtr = (int)*piPgno;
int i;
segmentPtrReset(&aPtr[0], LSM_SEGMENTPTR_FREE_THRESHOLD);
for(i=1; rc==LSM_OK && i<=nRhs && bStop==0; i++){
SegmentPtr *pPtr = &aPtr[i];
iOut = 0;
@@ -2868,7 +2873,7 @@ static int multiCursorEnd(MultiCursor *pCsr, int bLast){
int rc = LSM_OK;
int i;
pCsr->flags &= ~(CURSOR_NEXT_OK | CURSOR_PREV_OK);
pCsr->flags &= ~(CURSOR_NEXT_OK | CURSOR_PREV_OK | CURSOR_SEEK_EQ);
pCsr->flags |= (bLast ? CURSOR_PREV_OK : CURSOR_NEXT_OK);
pCsr->iFree = 0;
+72 -8
View File
@@ -1802,7 +1802,7 @@ static void jsonArrayStep(
jsonAppendValue(pStr, argv[0]);
}
}
static void jsonArrayFinal(sqlite3_context *ctx){
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
@@ -1811,16 +1811,66 @@ static void jsonArrayFinal(sqlite3_context *ctx){
if( pStr->bErr ){
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else{
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
pStr->nUsed--;
}
}else{
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
}
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonArrayValue(sqlite3_context *ctx){
jsonArrayCompute(ctx, 0);
}
static void jsonArrayFinal(sqlite3_context *ctx){
jsonArrayCompute(ctx, 1);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** This method works for both json_group_array() and json_group_object().
** It works by removing the first element of the group by searching forward
** to the first comma (",") that is not within a string and deleting all
** text through that comma.
*/
static void jsonGroupInverse(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
int i;
int inStr = 0;
char *z;
JsonString *pStr;
UNUSED_PARAM(argc);
UNUSED_PARAM(argv);
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
** always have been called to initalize it */
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
for(i=1; z[i]!=',' || inStr; i++){
assert( i<pStr->nUsed );
if( z[i]=='"' ){
inStr = !inStr;
}else if( z[i]=='\\' ){
i++;
}
}
pStr->nUsed -= i;
memmove(&z[1], &z[i+1], pStr->nUsed-1);
}
#else
# define jsonGroupInverse 0
#endif
/*
** json_group_obj(NAME,VALUE)
@@ -1852,7 +1902,7 @@ static void jsonObjectStep(
jsonAppendValue(pStr, argv[1]);
}
}
static void jsonObjectFinal(sqlite3_context *ctx){
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
@@ -1860,16 +1910,26 @@ static void jsonObjectFinal(sqlite3_context *ctx){
if( pStr->bErr ){
if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
assert( pStr->bStatic );
}else{
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed,
pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, pStr->nUsed, SQLITE_TRANSIENT);
pStr->nUsed--;
}
}else{
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
}
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
static void jsonObjectValue(sqlite3_context *ctx){
jsonObjectCompute(ctx, 0);
}
static void jsonObjectFinal(sqlite3_context *ctx){
jsonObjectCompute(ctx, 1);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -2377,9 +2437,12 @@ int sqlite3Json1Init(sqlite3 *db){
int nArg;
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
void (*xFinal)(sqlite3_context*);
void (*xValue)(sqlite3_context*);
} aAgg[] = {
{ "json_group_array", 1, jsonArrayStep, jsonArrayFinal },
{ "json_group_object", 2, jsonObjectStep, jsonObjectFinal },
{ "json_group_array", 1,
jsonArrayStep, jsonArrayFinal, jsonArrayValue },
{ "json_group_object", 2,
jsonObjectStep, jsonObjectFinal, jsonObjectValue },
};
#ifndef SQLITE_OMIT_VIRTUALTABLE
static const struct {
@@ -2397,9 +2460,10 @@ int sqlite3Json1Init(sqlite3 *db){
aFunc[i].xFunc, 0, 0);
}
for(i=0; i<sizeof(aAgg)/sizeof(aAgg[0]) && rc==SQLITE_OK; i++){
rc = sqlite3_create_function(db, aAgg[i].zName, aAgg[i].nArg,
rc = sqlite3_create_window_function(db, aAgg[i].zName, aAgg[i].nArg,
SQLITE_UTF8 | SQLITE_DETERMINISTIC, 0,
0, aAgg[i].xStep, aAgg[i].xFinal);
aAgg[i].xStep, aAgg[i].xFinal,
aAgg[i].xValue, jsonGroupInverse, 0);
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){
+67 -58
View File
@@ -1,5 +1,5 @@
C Fix\sa\sminor\sproblem\sin\sthe\scode\sfor\sdetermining\swhether\sor\snot\san\sSQL\nstatement\sis\sSQLITE_TOOBIG.
D 2018-06-30T20:00:35.632
C Experimental\sfix\sfor\sresetting\sdatabases\sthat\shave\sbeen\sdeemed\sread-only\sdue\nto\sa\scorrupt\s"read-version"\sheader\sfield.
D 2018-07-19T11:44:02.889
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6
@@ -36,6 +36,7 @@ F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure a46cba271ae08d635a1f331384c04563bdd37adb3d63cbdcffb1d91babfb64f5 x
F configure.ac 18c93e8bbeec8254832c4ea90eb06e7187fd150ef098baed02467eeb374afb17
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
F doc/lemon.html ac63db056bce24b7368e29319cd1a7eb5f1798cc85922d96a80b6c3a4ff9f51b
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
@@ -104,15 +105,15 @@ F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87
F ext/fts3/tool/fts3view.c 202801a2056995b763864d60c2dee744d46f1677
F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl ab0543a3b2399092ea2dd75df1bef333405b0d7f6b8c4951a0fbb60e780cb69f
F ext/fts3/unicode/parseunicode.tcl da577d1384810fb4e2b209bf3313074353193e95
F ext/fts3/unicode/mkunicode.tcl 0069320b64db6ee269c5e95f1f150d070fbf0a863fc7b3549d7e52bd068fb118
F ext/fts3/unicode/parseunicode.tcl 024ae0bdd96309d7b8fc479148191e9b3001dc74017a3f65f9a27de3b3ff968b
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
F ext/fts5/fts5.h 62f3e33ceeb9a428db139f9c012186b371da1cc7
F ext/fts5/fts5Int.h eda28e3a0a5d87c412e8355fe35da875b04cb389908c8eb0d867ad662adbc491
F ext/fts5/fts5Int.h 39f12034b598df4e0f59bbe6cf03af03a905a534b04f182d155641a04e1eb797
F ext/fts5/fts5_aux.c ca666a3bbe07c5a3bbe9fffaea19c935a1efaf337333e28bad7bdd1971ffd093
F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bfd13e973ff
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
F ext/fts5/fts5_expr.c c23a2e4c14c401a147c4a730460e5b37057627bf4be95515ee281cd87f4d277c
F ext/fts5/fts5_expr.c 5aef080ba3c8947e22f38ce1ff9fe548e4a740e72b77241f35ed941ae128d2c7
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
F ext/fts5/fts5_index.c 22b71d0e9e4b3ddd123a39ae27174e0012da2806f91b64087a68584f13f189de
F ext/fts5/fts5_main.c da46761a7e9b582083fcb9f5a3ee50086205fb91f4e68d984a9946e64218e297
@@ -120,8 +121,8 @@ F ext/fts5/fts5_storage.c 4bec8a1b3905978b22a67bca5f4a3cfdb94af234cf51efb36f4f2d
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
F ext/fts5/fts5_test_tok.c ffd657dd67e7fcdb31bf63fb60b6d867299a581d0f46e97086abacd66c2a9b26
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
F ext/fts5/fts5_tokenize.c ebd13d034f3dc7c841e1c32c364a4fca5cc2e05a0b91682a93fa1e6defcd4292
F ext/fts5/fts5_unicode2.c f074475acb251e9deb2fd4c72b2fe175f596ff25cf330fb044f869cf742da644
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
F ext/fts5/fts5_vocab.c 1cd79854cb21543e66507b25b0578bc1b20aa6a1349b7feceb8e8fed0e7a77a6
F ext/fts5/fts5parse.y eb526940f892ade5693f22ffd6c4f2702543a9059942772526eac1fde256bb05
@@ -145,6 +146,7 @@ F ext/fts5/test/fts5aux.test 8e7f9c96f8570f48402f2fd7b74e1ccfadd319fa56ef6773218
F ext/fts5/test/fts5auxdata.test eacc97ff04892f1a5f3d4df5a73f8bcbc3955ea1d12c9f24137eb1fc079e7611
F ext/fts5/test/fts5bigpl.test 6466c89b38439f0aba26ac09e232a6b963f29b1cbe1304f6a664fe1e7a8f5fd3
F ext/fts5/test/fts5bigtok.test 541119e616c637caea925a8c028c37c2c29e94383e00aa2f9198d530724b6e36
F ext/fts5/test/fts5cat.test daba0b80659460b0cb60bd1f40b402478a761fe7ea414c3c94c2be25568cc33a
F ext/fts5/test/fts5colset.test a30473451321bbf0b6218af62e96b4ae5fa99931cfdb210b5ecc804623b30f75
F ext/fts5/test/fts5columnsize.test 45459ce4dd9fd853b6044cdc9674921bff89e3d840f348ca8c1630f9edbf5482
F ext/fts5/test/fts5config.test 60094712debc59286c59aef0e6cf511c37d866802776a825ce437d26afe0817f
@@ -225,7 +227,7 @@ F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa510481
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
F ext/lsm1/lsm-test/README 87ea529d2abe615e856d4714bfe8bb185e6c2771b8612aa6298588b7b43e6f86
F ext/lsm1/lsm-test/lsmtest.h cf58528ffe0cfe535e91b44584e2ec5fb1caacdabecef0d8dcf83bf83168bf28
F ext/lsm1/lsm-test/lsmtest1.c 33158978327f800e82b6a47c09b86ace809f56a9ff10b0162273ec1186cc3153
F ext/lsm1/lsm-test/lsmtest1.c ae6ba48a0851b39be69a7d0eb220bfb9521a526e926223d5014bd385df10abb3
F ext/lsm1/lsm-test/lsmtest2.c 188b09aec776516aeedcfd13b9c6faf85ba16b3671a0897a2c740ee00a5dc4f8
F ext/lsm1/lsm-test/lsmtest3.c 9ab87528a36dbf4a61d7c8ad954f5ee368c0878c127b84b942b2e2abe522de26
F ext/lsm1/lsm-test/lsmtest4.c d258d6a245db5d8eaede096e2368d23f859c5e92c80ab9122463f708514fe10c
@@ -243,7 +245,7 @@ F ext/lsm1/lsm-test/lsmtest_mem.c 4e63c764345ab1df59d4f13a77980c6f3643798210b10d
F ext/lsm1/lsm-test/lsmtest_tdb.c 618a8619183fda4f5540fcde15f9068293c5e3180e1a246e34409b0c148758b3
F ext/lsm1/lsm-test/lsmtest_tdb.h 8733eee249b12956a9df8322994b43d19bd8c02ad2e8b0bb5164db4d6ccc1735
F ext/lsm1/lsm-test/lsmtest_tdb2.cc 99ea7f2dd9c7536c8fb9bdd329e4cfeb76899f3ddf6f48bdd3926e016922b715
F ext/lsm1/lsm-test/lsmtest_tdb3.c b4e46b1d2fec553fe4efb44e341b43abd20556fde610db0cfffdc2300b72defe
F ext/lsm1/lsm-test/lsmtest_tdb3.c 7a7ccae189f5bb25bcd1ec3bbd740529706eded7f6729a5a0a9eeaeb57785320
F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e541e35fcda61ebf1d277f
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
@@ -256,7 +258,7 @@ F ext/lsm1/lsm_main.c b5703f8042e71d3a2d65e671f6832e077e79e89e9975818f67f9699226
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
F ext/lsm1/lsm_sorted.c df7b393d9e4b85e6ad07181c6434d58a69a9145ee925d89c3ee1d2a210adaf9a
F ext/lsm1/lsm_sorted.c 6f7d8cf7a7d3d3f1ab5d9ba6347e8f39f3d73c00ec48afcd0c4bcbefd806f9b8
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
@@ -281,7 +283,7 @@ F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0
F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
F ext/misc/json1.c 02f5f0d9c131df79f4ee168d2b426f0f0d273b7771fc0bb5293c4e7692d9a2ee
F ext/misc/json1.c 933ace99a1880e014f35fbf6444fb24e3cf9920c3a6a75e9aa70f0caf683e3fe
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
@@ -430,16 +432,16 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 6beb476095a4cfeb95ebedb2e5e17894d1687b24fddd5b8761a4de120e0392c6
F src/analyze.c 41f0b8d638fc2a7309477904ac38e535f2aabea3256da3251e529730e099df77
F src/analyze.c 91b5e7c0f4a08dbb1f7a24b24e7ab49be8b0a2fd1906a35add62a855d1c0ceb9
F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a
F src/auth.c a38f3c63c974787ecf75e3213f8cac6568b9a7af7591fb0372ec0517dd16dca8
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c bb23e5470ec0c9b9ae8e17c86cb686bc4112642d8f457bd42b3b3727d5ef78be
F src/btree.c 4b91880ab0f6595c52f13b17f3ef269062073341c254311b3c38925db5b89b9a
F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
F src/build.c 3b3bfa88800739e1f11313dcecfba5ef8e4757b6c929cdf7de9fcfc01002b81f
F src/build.c d8f6ac1e9e484eb3f3921a8336d3dc6c87273d9db8729702162ef045997a1463
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 849d4cebe008cfc6e4799b034a172b4eaf8856b100739632a852732ba66eee48
@@ -447,19 +449,19 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
F src/expr.c 7e257eeffe9553c10a6ac0a1f0177bf740c4da834e7d6e2cbb7d3ebaa3d7f3e1
F src/expr.c bb148f4c45b6e53b5b58a912974253547e8862685cb001fbdfaef0ab24812e6f
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
F src/func.c d2c66d8ec930d53e9ecd0d6cbe210c1a70f0427bfc49624516fb97aae2f5cfe8
F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c bcacf6a0d277f8fa0e4f9ffecda544a2330ca4478f904cd89564c2dd86d0b16b
F src/insert.c 8613af9c5ba1503bc68f4e9432c6c024e0fdafdc791575c50f380f73ec91189f
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
F src/main.c 0087639013e4b62ce16a92e4b0cb6127876224fadeea72016396626078dc8736
F src/main.c 9c8ef68bd3779d493d632946b3a65156b2e636ad2c7a1b7cd1450e87dc0c6a7d
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -482,9 +484,9 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c c230a7a24766320d8414afd087edcd43e499fb45e86361f6f4f464f343d965a9
F src/os_win.c ac29c25cde4cfb4adacc59cdec4aa45698ca0e29164ea127859585ccd9faa354
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 1bb6a57fa0465296a4d6109a1a64610a0e7adde1f3acf3ef539a9d972908ce8f
F src/pager.c 29c48653efacf4f3a0b0e193515b789a1e9eee7d232816704cef95216906baa3
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
F src/parse.y 9b57f1d0d3d7578ab2917e07ff5d8def4b0aac571113dd7b7cb8108e7194d025
F src/parse.y 3bd43415ea974b9921b0ff2c0bd3e9100f6e501ede0b6d3b90cca2ab6af25485
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
@@ -493,19 +495,19 @@ F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c d8359c59c683fc33324c3a0abe0d393304861f05dd2e0d47e5974a501bcf4682
F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 82aa95aa1cfeadef5ecae1126afff1efca64c49050bbf7116425a8a1d4fc5e6c
F src/shell.c.in 8578421c5fb2a972461b2a996f7173646e55e0dbd2a2eee30c8f5dc7d3dbadfd
F src/sqlite.h.in 243e0b1d302c237372c06002fe84f731fd22587eccd142d15de834a5296514ff
F src/select.c 2e9661d4424f43ccf595c4a7b4acdf32db523c0f6b31cbd62e6e5a2f43118981
F src/shell.c.in 239aee5570703fcbf9e6bec176a3ba7704bf327515f9f0dbd2498f00746e82b6
F src/sqlite.h.in 6203acde410e38d96ffb24e9b6349f87eb80914ba5676466ac5d8478b6b8f144
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h c14c850bf0c4dd3860cc5092f140ae9faf93b77737b3febf38454088e1ab3988
F src/sqliteInt.h c2ceebe60d1d2e11674b90c8b55fdffd91386ce8d7ae38613fbcc61659b8fcac
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c 916a92de77ec5cbe27818ca194d8cf0c58aa7ad5b87527098f6aa5a6068800ce
F src/test1.c b5e21f2ec8386cabb67346c9399603ddb33f76094a0941f280b403aa93631717
F src/test1.c 335740ddc632c0b54765b6fd373da7f76a397adde3ded3592390dd1e5fb0dd55
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
@@ -551,28 +553,28 @@ F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
F src/test_vfs.c 112f1f9271c33c211812e0e681830a84262dac065da58579ff49f9cefec97d4f
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
F src/test_window.c add59ee68568868129516999f30a68e8ab2afd276e272aba4f633c9fc52c1bb1
F src/test_window.c 0d19b33e7a262d3b55e85bc0fb84a70f503686cbd769939176162fe866ce7f9e
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c e0a90f3d594e3db842581543abf157c8e63617655c91ad35d77e339a1bc36ce0
F src/treeview.c 2c5c4bc0a443401db5fd621542150452ddf5055d38edd4eef868bc2b6bfb0260
F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b97
F src/treeview.c 462346b82a892316a62291791c77e3dd5f1927745fe4a44b846ab4fd16eb28c3
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
F src/update.c 46dc24c6158446aaab45caee09b6d99327cb479268b83ffeb5b701823da3b67b
F src/update.c 7b7c768dc415a8d2eb9fd2cea8b524cb29cf354f319700e22f94f262d3f507cb
F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
F src/vdbe.c 37b942ccdd224dd51bd80312b8d236f27c7c728e76c3f425c50e9d8ecff3b7b4
F src/vdbe.h 847735b3e083285aa225d2bf1fe97107a0a2b8942c80d643cdb764990705820d
F src/vdbe.c 9933ec035072c72fc26c5439f6c8a1eef902ce9132916d5a05e8733b0266eb67
F src/vdbe.h d93abdc8bc9295e0a256e582c19f548c545dc498319d108bbc9dd29de31c48a2
F src/vdbeInt.h 6b5cbd338dc9aaad343fb11b455e47463b0474d9f79710f50e647158941146e0
F src/vdbeapi.c e35f813312b0f6e8e2835b357f121e0d1da6d3013bac3e367fe4efd518e7a2ec
F src/vdbeapi.c af4a3de00d1851bcbc55b85dfbe52849aa2b1e17b4a5a1f3d9c257df7af361ff
F src/vdbeaux.c c2d65c763b0811afe409e02e9d0d1f300c6e97892474fc94eec3da71955cd418
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 87b48c0bd68041a61fb3f4e18a1a696f5339d65e572d288a266a602a01863f1a
F src/vdbemem.c a699a1d7ccc3f94cdff69ddf35d5f7540dbf52ca44cf040eda3c87520e67858c
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 10ea07dec111de6fb0a4fc87a7ffa4c65fdc088a19dbfaf7d6f2b128f2e8eb7b
@@ -580,11 +582,11 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6
F src/where.c cd6710e24d3d5c29d6890df93865c22d896453907eb83988c505a3098e90179f
F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
F src/whereexpr.c 19cf35cdd9bf6d5589d8a5c960d99259761136187a2319a6e14d11cf1abe14c2
F src/window.c 4403ae36b9645f105ad8ae16d986929c6db5f3bc7d3d3db43f5fa51c6bbfcbe8
F src/wherecode.c fe23a55294b4c94bf658d2a6eb7996170dd563bf33af4c3e5d71aff3483e4b08
F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a
F src/window.c c61434ce7e35b7d76b3321dec39e10e79061c10eed1e3d7976c87dbdd77aefb5
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -620,6 +622,7 @@ F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
F test/atof1.test ff0b0156fd705b67c506e1f2bfe9e26102bea9bd
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
F test/attach.test f4b8918ba2f3e88e6883b8452340545f10a1388af808343c37fc5c577be8281c
F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3a0ce
F test/attach3.test c59d92791070c59272e00183b7353eeb94915976
@@ -746,6 +749,7 @@ F test/csv01.test 6e1445b3207d574cff22fc41a8e549dfcf2466ee90546ada97d22a90fa89eb
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 0078ae1ded4afcf5eb80d06e3a72b6e1c3f1a646aab26eeb583b0a9ec6f0d56e
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
@@ -1028,7 +1032,7 @@ F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd7
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test b40a9f5395d8e669b0bc3eb550ad2ae9e5ada01fbce23c446c2a30a305a6d575
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
F test/json103.test aff6b7a4c17d5a20b487a7bc1a274bfdc63b829413bdfb83bedac42ec7f67e3b
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/kvtest.c 94da54bb66aae7a54e47cf7e4ea4acecc0f217560f79ad3abfcc0361d6d557ba
@@ -1151,7 +1155,7 @@ F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 5c2167e03dc55ff697e11bb3abf10c66ba452e4afb2dbd85a2b144048355300e
F test/pg_common.tcl 3bf36b30d7b09e5896a1fb0268ace22f2ebfa91d07a422d8ffbf57551d9ce0dc
F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
@@ -1177,7 +1181,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl 769892f81050b3f59c66f274d478d855159b474ea27019dec82f1215c0b91ef7 x
F test/resetdb.test 2107b34a8c437183f48eb833905df43818160a55f4ac69bbaf54f356fb2b27bd
F test/resetdb.test b7df373608a56b1fc7a9ed942e8d91fa3ad25b87b63bdb36c88811ad1d0a9c90
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
@@ -1211,6 +1215,7 @@ F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b
F test/schemafault.test 1936bceca55ac82c5efbcc9fc91a1933e45c8d1e1d106b9a7e56c972a5a2a51e
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test 2e760bab8f3658b3b97debcf52860d0d2e20aa6cbe8b40e678ddb99871a15491
@@ -1225,7 +1230,7 @@ F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
F test/selectA.test b8a590f6493cad5b0bb4dfe1709bf7dcda0b6c40bb4caf32d1e36a89eebc8fc5
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
F test/selectC.test e25243f8ca503e06f252eb0218976d07cfeceac3
F test/selectD.test cfa9f27dbdbeaf2d021d26c79b6c790d8f26e5506d50117c7696d3e136d6d9e7
F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0d214
F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840
@@ -1257,7 +1262,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
F test/skipscan1.test 8ab5d2c7c5cd3fe7f172d366e6e74e887cb33cb4
F test/skipscan1.test 3ea1cccca8f1b0e1cf3e73a63b43dd796f34d4aaee815e641f0d2ebb3fa448d4
F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b5fb763
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
@@ -1323,7 +1328,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl aa7558f20fcf7dd9151325f849d9103bd450235093bc078073bf0f080991e3c4
F test/tester.tcl d5138d226cc2aaacb6934cdd79acaa5edd17cad862482895b833bbf62c49aca0
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1518,7 +1523,7 @@ F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
F test/update2.test 5e67667e1c54017d964e626db765cf8bedcf87483c184f4c575bdb8c1dd2313e
F test/upsert1.test d587db593f131e112a98a05685c418e0eacc28df5905403e4ca04cd74c39a3fc
F test/upsert1.test ecd8f69e20183f298464992762fee24750508b3cbefc5badba8a259a3fc887ec
F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
@@ -1583,6 +1588,7 @@ F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
F test/walprotocol.test a112aba0b79e3adeaa485fed09484b32c654e97df58e454aa8489ac2cd57bf84
F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
@@ -1621,13 +1627,13 @@ F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 7cb260079cd88d6d6177b0f592686f2bbbc2d10f4f415c8a37cd153eb83c87ca
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
F test/window3.tcl 9b82055c8977bdcab164fb4f71dabf86c511c9010c44f958352b610d313182c3
F test/window3.test 47884c240d0d5234ad9c6da65452cfec1bfa69ec6f9c4158cd9750c3d88d3a25
F test/window4.tcl 7cec7e578aa9f78b7265bff8d552cda17a1d8d89f0449d0e74970a527b8846f5
F test/window4.test dcd8767869988e0d23d56bc3f8b46ec116de23127b81b5f66fd48d5529072ed1
F test/window5.test a4835b96d30eb3b81a1dbc683e333e57a614645eb6f2ae476a7ed2addf0b0f1f
F test/window6.test fb4e464993630c3d6023e906aa6705667062600a8341085b7fd8c201f4c2f411
F test/windowfault.test 97d5fc404308edb579a5a183e294ed874c844ecf01f0a28ba46df3141ebaee1f
F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823
F test/window3.test e274b7f8952ca4ed25996e0e45c047192b066e0aaff2a822d4293c8c4f1d8d98
F test/window4.tcl 871364059b7d320d556ec6ef804d604a4e8cc1547a3102c5d56067371bb200af
F test/window4.test 323b118eb592932036388643ca6dcaead87f699bbea2984bbca49ba4ad6c2509
F test/window5.test 8187f46597c90b73e8f96659e893353cbda337479cc582f7a488eab351ba08d3
F test/window6.test 7574778c79cae89f1781df237bf9ff5063886deca91a36efc53934315f0e7612
F test/windowfault.test 23abad97b72c6f609002255ddd41ef5c8922408f918f9b98ad6005ab316e482f
F test/with1.test 58475190cd8caaeebea8cfeb2a264ec97a0c492b8ffe9ad20cefbb23df462f96
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
F test/with3.test 5e8ce2c585170bbbc0544e2a01a4941fa0be173ba5265e5c92eb588cd99a232d
@@ -1664,7 +1670,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
F tool/lemon.c 33892e2a243865f73e6c6e7cecce3c6eb4bb95db4a3d9d86d146c8064feb92fd
F tool/lempar.c 6f64bc81160495f93d0f2ae27c787cb7cf4d5c7f5d2abf3823bc878ded6d6293
F tool/lempar.c 428a050780425be2d699e939605fcbc54a161c20884f11b476b2eea961394bbe
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
@@ -1744,7 +1750,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P aad718fb1afacf1c921966796ab1e149207c31b16409c5672f0371f4fb9d6565
R 6cfae24b0260985fdb1b9447231b1548
P a5087c5c87ad65f92e3bc96bbc84afb43faf10ab6b9ed3ba16304b5c60ad069f
R cc038e87dc659a807799369c4759d0af
T *branch * exp-dbreset-fix
T *sym-exp-dbreset-fix *
T -sym-trunk *
U dan
Z 6c2f201187f4c45767b497733a8a927a
Z c2723926c6d15ad4b82159593e2d431c
+1 -1
View File
@@ -1 +1 @@
763e6c9e2bbc0a6ef8d8361069bf7160790c9064f24f0e336b7ed85668735da9
e2394002d02754bb45d56e805df9bc5a2ef0d14e5d94262c1f8ab7643bc27c8f
+1 -4
View File
@@ -1274,10 +1274,7 @@ static void analyzeOneTable(
callStatGet(v, regStat4, STAT_GET_NLT, regLt);
callStatGet(v, regStat4, STAT_GET_NDLT, regDLt);
sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
/* We know that the regSampleRowid row exists because it was read by
** the previous loop. Thus the not-found jump of seekOp will never
** be taken */
VdbeCoverageNeverTaken(v);
VdbeCoverage(v);
#ifdef SQLITE_ENABLE_STAT3
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
#else
+15 -2
View File
@@ -3316,6 +3316,12 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
}
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
if( (p->db->flags & SQLITE_ResetDatabase)
&& sqlite3PagerIsreadonly(pBt->pPager)==0
){
pBt->btsFlags &= ~BTS_READ_ONLY;
}
/* Write transactions are not possible on a read-only database */
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
rc = SQLITE_READONLY;
@@ -3375,6 +3381,11 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
/* if there was no transaction opened when this function was
** called and SQLITE_BUSY_SNAPSHOT is returned, change the error
** code to SQLITE_BUSY. */
rc = SQLITE_BUSY;
}
}
}
@@ -3426,7 +3437,6 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
}
}
trans_begun:
if( rc==SQLITE_OK ){
if( pSchemaVersion ){
@@ -5192,7 +5202,10 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*/
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3BtreeSkipNext(BtCursor *pCur){
if( pCur->eState==CURSOR_VALID ){
/* We believe that the cursor must always be in the valid state when
** this routine is called, but the proof is difficult, so we add an
** ALWaYS() test just in case we are wrong. */
if( ALWAYS(pCur->eState==CURSOR_VALID) ){
pCur->eState = CURSOR_SKIPNEXT;
pCur->skipNext = 1;
}
+6 -1
View File
@@ -1788,7 +1788,7 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
assert( pParse->pNewTable==pTab );
sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0,
SQLITE_IDXTYPE_PRIMARYKEY);
if( db->mallocFailed ) return;
if( db->mallocFailed || pParse->nErr ) return;
pPk = sqlite3PrimaryKeyIndex(pTab);
pTab->iPKey = -1;
}else{
@@ -2319,6 +2319,11 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
nErr++;
}
pTable->pSchema->schemaFlags |= DB_UnresetViews;
if( db->mallocFailed ){
sqlite3DeleteColumnNames(db, pTable);
pTable->aCol = 0;
pTable->nCol = 0;
}
#endif /* SQLITE_OMIT_VIEW */
return nErr;
}
+16 -1
View File
@@ -1487,7 +1487,7 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *pDup, int flags){
pNew->pWin = 0;
pNew->pWinDefn = sqlite3WindowListDup(db, p->pWinDefn);
#endif
sqlite3SelectSetName(pNew, p->zSelName);
pNew->selId = p->selId;
*pp = pNew;
pp = &pNew->pPrior;
pNext = pNew;
@@ -4951,6 +4951,21 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){
if( pA->iTable!=pB->iTable
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
}
#ifndef SQLITE_OMIT_WINDOWFUNC
/* Justification for the assert():
** window functions have p->op==TK_FUNCTION but aggregate functions
** have p->op==TK_AGG_FUNCTION. So any comparison between an aggregate
** function and a window function should have failed before reaching
** this point. And, it is not possible to have a window function and
** a scalar function with the same name and number of arguments. So
** if we reach this point, either A and B both window functions or
** neither are a window functions. */
assert( (pA->pWin==0)==(pB->pWin==0) );
if( pA->pWin!=0 ){
if( sqlite3WindowCompare(pParse,pA->pWin,pB->pWin)!=0 ) return 2;
}
#endif
}
return 0;
}
+41 -16
View File
@@ -1505,7 +1505,7 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
i64 v = sqlite3_value_int64(argv[0]);
p->rSum += v;
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
p->overflow = 1;
p->approx = p->overflow = 1;
}
}else{
p->rSum += sqlite3_value_double(argv[0]);
@@ -1521,17 +1521,18 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
UNUSED_PARAMETER(argc);
p = sqlite3_aggregate_context(context, sizeof(*p));
type = sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
/* p is always non-NULL because sumStep() will have been called first
** to initialize it */
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
if( type==SQLITE_INTEGER ){
assert( type==SQLITE_INTEGER || p->approx );
if( type==SQLITE_INTEGER && p->approx==0 ){
i64 v = sqlite3_value_int64(argv[0]);
p->rSum -= v;
if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, -1*v) ){
p->overflow = 1;
}
p->iSum -= v;
}else{
p->rSum += sqlite3_value_double(argv[0]);
p->approx = 1;
p->rSum -= sqlite3_value_double(argv[0]);
}
}
}
@@ -1572,6 +1573,9 @@ static void totalFinalize(sqlite3_context *context){
typedef struct CountCtx CountCtx;
struct CountCtx {
i64 n;
#ifdef SQLITE_DEBUG
int bInverse; /* True if xInverse() ever called */
#endif
};
/*
@@ -1589,7 +1593,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
** sure it still operates correctly, verify that its count agrees with our
** internal count when using count(*) and when the total count can be
** expressed as a 32-bit integer. */
assert( argc==1 || p==0 || p->n>0x7fffffff
assert( argc==1 || p==0 || p->n>0x7fffffff || p->bInverse
|| p->n==sqlite3_aggregate_count(context) );
#endif
}
@@ -1598,6 +1602,21 @@ static void countFinalize(sqlite3_context *context){
p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int64(context, p ? p->n : 0);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void countInverse(sqlite3_context *ctx, int argc, sqlite3_value **argv){
CountCtx *p;
p = sqlite3_aggregate_context(ctx, sizeof(*p));
/* p is always non-NULL since countStep() will have been called first */
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && ALWAYS(p) ){
p->n--;
#ifdef SQLITE_DEBUG
p->bInverse = 1;
#endif
}
}
#else
# define countInverse 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Routines to implement min() and max() aggregate functions.
@@ -1652,13 +1671,13 @@ static void minMaxValueFinalize(sqlite3_context *context, int bValue){
}
#ifndef SQLITE_OMIT_WINDOWFUNC
static void minMaxValue(sqlite3_context *context){
return minMaxValueFinalize(context, 1);
minMaxValueFinalize(context, 1);
}
#else
# define minMaxValue 0
#endif /* SQLITE_OMIT_WINDOWFUNC */
static void minMaxFinalize(sqlite3_context *context){
return minMaxValueFinalize(context, 0);
minMaxValueFinalize(context, 0);
}
/*
@@ -1703,16 +1722,20 @@ static void groupConcatInverse(
sqlite3_value **argv
){
int n;
assert( argc==1 || argc==2 );
StrAccum *pAccum;
assert( argc==1 || argc==2 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum));
if( pAccum ){
/* pAccum is always non-NULL since groupConcatStep() will have always
** run frist to initialize it */
if( ALWAYS(pAccum) ){
n = sqlite3_value_bytes(argv[0]);
if( argc==2 ){
n += sqlite3_value_bytes(argv[1]);
}else{
n++;
}
if( n>=pAccum->nChar ){
if( n>=(int)pAccum->nChar ){
pAccum->nChar = 0;
}else{
pAccum->nChar -= n;
@@ -1943,8 +1966,10 @@ void sqlite3RegisterBuiltinFunctions(void){
WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0),
WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0),
WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0),
AGGREGATE2(count, 0,0,0, countStep, countFinalize, SQLITE_FUNC_COUNT ),
WAGGREGATE(count, 1,0,0, countStep, countFinalize, 0, 0, 0 ),
WAGGREGATE(count, 0,0,0, countStep,
countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ),
WAGGREGATE(count, 1,0,0, countStep,
countFinalize, countFinalize, countInverse, 0 ),
WAGGREGATE(group_concat, 1, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
+4 -4
View File
@@ -1632,6 +1632,10 @@ void sqlite3GenerateConstraintChecks(
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
if( aRegIdx[ix]==0 ) continue; /* Skip indices that do not change */
if( bAffinityDone==0 ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
if( pUpIdx==pIdx ){
addrUniqueOk = sAddr.upsertBtm;
upsertBypass = sqlite3VdbeGoto(v, 0);
@@ -1641,10 +1645,6 @@ void sqlite3GenerateConstraintChecks(
addrUniqueOk = sqlite3VdbeMakeLabel(v);
}
VdbeNoopComment((v, "uniqueness check for %s", pIdx->zName));
if( bAffinityDone==0 ){
sqlite3TableAffinity(v, pTab, regNewData+1);
bAffinityDone = 1;
}
iThisCur = iIdxCur+ix;
+15 -10
View File
@@ -1291,7 +1291,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
sqlite3VtabRollback(db);
sqlite3EndBenignMalloc();
if( (db->mDbFlags&DBFLAG_SchemaChange)!=0 && db->init.busy==0 ){
if( schemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
}
@@ -1692,13 +1692,14 @@ int sqlite3CreateFunc(
int extraFlags;
assert( sqlite3_mutex_held(db->mutex) );
if( zFunctionName==0 ||
(xSFunc && (xFinal || xStep)) ||
(!xSFunc && (xFinal && !xStep)) ||
(!xSFunc && (!xFinal && xStep)) ||
((xValue || xInverse) && (!xStep || !xFinal || !xValue || !xInverse)) ||
(nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG) ||
(255<(nName = sqlite3Strlen30( zFunctionName))) ){
assert( xValue==0 || xSFunc==0 );
if( zFunctionName==0 /* Must have a valid name */
|| (xSFunc!=0 && xFinal!=0) /* Not both xSFunc and xFinal */
|| ((xFinal==0)!=(xStep==0)) /* Both or neither of xFinal and xStep */
|| ((xValue==0)!=(xInverse==0)) /* Both or neither of xValue, xInverse */
|| (nArg<-1 || nArg>SQLITE_MAX_FUNCTION_ARG)
|| (255<(nName = sqlite3Strlen30( zFunctionName)))
){
return SQLITE_MISUSE_BKPT;
}
@@ -1739,7 +1740,7 @@ int sqlite3CreateFunc(
** operation to continue but invalidate all precompiled statements.
*/
p = sqlite3FindFunction(db, zFunctionName, nArg, (u8)enc, 0);
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==enc && p->nArg==nArg ){
if( p && (p->funcFlags & SQLITE_FUNC_ENCMASK)==(u32)enc && p->nArg==nArg ){
if( db->nVdbeActive ){
sqlite3ErrorWithMsg(db, SQLITE_BUSY,
"unable to delete/modify user-function due to active statements");
@@ -3710,6 +3711,9 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
}else if( op==SQLITE_FCNTL_JOURNAL_POINTER ){
*(sqlite3_file**)pArg = sqlite3PagerJrnlFile(pPager);
rc = SQLITE_OK;
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
rc = SQLITE_OK;
}else{
rc = sqlite3OsFileControl(fd, op, pArg);
}
@@ -3973,7 +3977,8 @@ int sqlite3_test_control(int op, ...){
*/
case SQLITE_TESTCTRL_VDBE_COVERAGE: {
#ifdef SQLITE_VDBE_COVERAGE
typedef void (*branch_callback)(void*,int,u8,u8);
typedef void (*branch_callback)(void*,unsigned int,
unsigned char,unsigned char);
sqlite3GlobalConfig.xVdbeBranch = va_arg(ap,branch_callback);
sqlite3GlobalConfig.pVdbeBranchArg = va_arg(ap,void*);
#endif
+31 -18
View File
@@ -1764,7 +1764,6 @@ static void pager_reset(Pager *pPager){
** Return the pPager->iDataVersion value
*/
u32 sqlite3PagerDataVersion(Pager *pPager){
assert( pPager->eState>PAGER_OPEN );
return pPager->iDataVersion;
}
@@ -6382,9 +6381,10 @@ int sqlite3PagerCommitPhaseOne(
** backup in progress needs to be restarted. */
sqlite3BackupRestart(pPager->pBackup);
}else{
PgHdr *pList;
if( pagerUseWal(pPager) ){
PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache);
PgHdr *pPageOne = 0;
pList = sqlite3PcacheDirtyList(pPager->pPCache);
if( pList==0 ){
/* Must have at least one page for the WAL commit flag.
** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */
@@ -6405,14 +6405,14 @@ int sqlite3PagerCommitPhaseOne(
** should be used. No rollback journal is created if batch-atomic-write
** is enabled.
*/
sqlite3_file *fd = pPager->fd;
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
sqlite3_file *fd = pPager->fd;
int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
&& !pPager->noSync
&& sqlite3JournalIsInMemory(pPager->jfd);
#else
# define bBatch 0
# define bBatch 0
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
@@ -6464,15 +6464,16 @@ int sqlite3PagerCommitPhaseOne(
}
}
}
#else
#else /* SQLITE_ENABLE_ATOMIC_WRITE */
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( zMaster ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
assert( bBatch==0 );
}
#endif
rc = pager_incr_changecounter(pPager, 0);
#endif
#endif /* !SQLITE_ENABLE_ATOMIC_WRITE */
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write the master journal name into the journal file. If a master
@@ -6496,23 +6497,35 @@ int sqlite3PagerCommitPhaseOne(
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
pList = sqlite3PcacheDirtyList(pPager->pPCache);
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( bBatch ){
/* The pager is now in DBMOD state. But regardless of what happens
** next, attempting to play the journal back into the database would
** be unsafe. Close it now to make sure that does not happen. */
sqlite3OsClose(pPager->jfd);
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
if( bBatch ){
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
rc = pager_write_pagelist(pPager, pList);
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
if( rc!=SQLITE_OK ){
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
}
}
if( rc!=SQLITE_OK ){
sqlite3OsFileControlHint(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
if( (rc&0xFF)==SQLITE_IOERR && rc!=SQLITE_IOERR_NOMEM ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ){
sqlite3OsClose(pPager->jfd);
}
bBatch = 0;
}else{
sqlite3OsClose(pPager->jfd);
}
}
#endif /* SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
if( bBatch==0 && rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
}
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
+34 -54
View File
@@ -531,15 +531,12 @@ multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/}
%endif SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q)
%ifndef SQLITE_OMIT_WINDOWFUNC
windowdefn_opt(R)
%endif
orderby_opt(Z) limit_opt(L). {
#if SELECTTRACE_ENABLED
Token s = S; /*A-overwrites-S*/
#endif
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( A ){
@@ -547,30 +544,7 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
}else{
sqlite3WindowListDelete(pParse->db, R);
}
#endif // SQLITE_OMIT_WINDOWFUNC
#if SELECTTRACE_ENABLED
/* Populate the Select.zSelName[] string that is used to help with
** query planner debugging, to differentiate between multiple Select
** objects in a complex query.
**
** If the SELECT keyword is immediately followed by a C-style comment
** then extract the first few alphanumeric characters from within that
** comment to be the zSelName value. Otherwise, the label is #N where
** is an integer that is incremented with each SELECT statement seen.
*/
if( A!=0 ){
const char *z = s.z+6;
int i;
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName,"#%d",++pParse->nSelect);
while( z[0]==' ' ) z++;
if( z[0]=='/' && z[1]=='*' ){
z += 2;
while( z[0]==' ' ) z++;
for(i=0; sqlite3Isalnum(z[i]); i++){}
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z);
}
}
#endif /* SELECTRACE_ENABLED */
#endif /* SQLITE_OMIT_WINDOWFUNC */
}
oneselect(A) ::= values(A).
@@ -1028,10 +1002,10 @@ expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A = sqlite3ExprFunction(pParse, Y, &X);
sqlite3WindowAttach(pParse, A, Z);
if( D==SF_Distinct && A ){
A->flags |= EP_Distinct;
}
sqlite3WindowAttach(pParse, A, Z);
}
expr(A) ::= id(X) LP STAR RP
%ifndef SQLITE_OMIT_WINDOWFUNC
@@ -1605,17 +1579,18 @@ wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
//
%ifndef SQLITE_OMIT_WINDOWFUNC
%type windowdefn_list {Window*}
%destructor windowdefn_list {sqlite3WindowDelete(pParse->db, $$);}
%destructor windowdefn_list {sqlite3WindowListDelete(pParse->db, $$);}
windowdefn_list(A) ::= windowdefn(Z). { A = Z; }
windowdefn_list(A) ::= windowdefn_list(Y) COMMA windowdefn(Z). {
if( Z ) Z->pNextWin = Y;
assert( Z!=0 );
Z->pNextWin = Y;
A = Z;
}
%type windowdefn {Window*}
%destructor windowdefn {sqlite3WindowDelete(pParse->db, $$);}
windowdefn(A) ::= nm(X) AS window(Y). {
if( Y ){
if( ALWAYS(Y) ){
Y->zName = sqlite3DbStrNDup(pParse->db, X.z, X.n);
}
A = Y;
@@ -1627,10 +1602,6 @@ windowdefn(A) ::= nm(X) AS window(Y). {
%type frame_opt {Window*}
%destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);}
%type window_or_nm {Window*}
%destructor window_or_nm {
sqlite3WindowDelete(pParse->db, $$);}
%type part_opt {ExprList*}
%destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);}
@@ -1641,18 +1612,14 @@ sqlite3WindowDelete(pParse->db, $$);}
%type frame_bound {struct FrameBound}
%destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);}
window_or_nm(A) ::= window(Z). {A = Z;}
window_or_nm(A) ::= nm(Z). {
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( A ){
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
}
}
%type frame_bound_s {struct FrameBound}
%destructor frame_bound_s {sqlite3ExprDelete(pParse->db, $$.pExpr);}
%type frame_bound_e {struct FrameBound}
%destructor frame_bound_e {sqlite3ExprDelete(pParse->db, $$.pExpr);}
window(A) ::= LP part_opt(X) orderby_opt(Y) frame_opt(Z) RP. {
A = Z;
if( A ){
if( ALWAYS(A) ){
A->pPartition = X;
A->pOrderBy = Y;
}
@@ -1664,36 +1631,49 @@ part_opt(A) ::= . { A = 0; }
frame_opt(A) ::= . {
A = sqlite3WindowAlloc(pParse, TK_RANGE, TK_UNBOUNDED, 0, TK_CURRENT, 0);
}
frame_opt(A) ::= range_or_rows(X) frame_bound(Y). {
frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y). {
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0);
}
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound(Y) AND frame_bound(Z). {
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND frame_bound_e(Z). {
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr);
}
range_or_rows(A) ::= RANGE. { A = TK_RANGE; }
range_or_rows(A) ::= ROWS. { A = TK_ROWS; }
frame_bound(A) ::= UNBOUNDED PRECEDING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; }
frame_bound_s(A) ::= frame_bound(X). { A = X; }
frame_bound_s(A) ::= UNBOUNDED PRECEDING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
frame_bound_e(A) ::= frame_bound(X). { A = X; }
frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; }
frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; }
frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; }
frame_bound(A) ::= UNBOUNDED FOLLOWING. { A.eType = TK_UNBOUNDED; A.pExpr = 0; }
%type windowdefn_opt {Window*}
%destructor windowdefn_opt {sqlite3WindowDelete(pParse->db, $$);}
%destructor windowdefn_opt {sqlite3WindowListDelete(pParse->db, $$);}
windowdefn_opt(A) ::= . { A = 0; }
windowdefn_opt(A) ::= WINDOW windowdefn_list(B). { A = B; }
%type over_opt {Window*}
%destructor over_opt {sqlite3WindowDelete(pParse->db, $$);}
over_opt(A) ::= . { A = 0; }
over_opt(A) ::= filter_opt(W) OVER window_or_nm(Z). {
over_opt(A) ::= filter_opt(W) OVER window(Z). {
A = Z;
if( A ) A->pFilter = W;
assert( A!=0 );
A->pFilter = W;
}
over_opt(A) ::= filter_opt(W) OVER nm(Z). {
A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( A ){
A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n);
A->pFilter = W;
}else{
sqlite3ExprDelete(pParse->db, W);
}
}
filter_opt(A) ::= . { A = 0; }
filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
%endif // SQLITE_OMIT_WINDOWFUNC
%endif /* SQLITE_OMIT_WINDOWFUNC */
+18 -1
View File
@@ -758,7 +758,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( is_agg==0 && pExpr->pWin ){
assert( is_agg==0 || (pDef->funcFlags & SQLITE_FUNC_MINMAX)
|| (pDef->xValue==0 && pDef->xInverse==0)
|| (pDef->xValue && pDef->xInverse && pDef->xSFunc && pDef->xFinalize)
);
if( pDef && pDef->xValue==0 && pExpr->pWin ){
sqlite3ErrorMsg(pParse,
"%.*s() may not be used as a window function", nId, zId
);
@@ -1239,6 +1243,19 @@ static int resolveOrderGroupBy(
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pE->pWin ){
/* Since this window function is being changed into a reference
** to the same window function the result set, remove the instance
** of this window function from the Select.pWin list. */
Window **pp;
for(pp=&pSelect->pWin; *pp; pp=&(*pp)->pNextWin){
if( *pp==pE->pWin ){
*pp = (*pp)->pNextWin;
}
}
}
#endif
pItem->u.x.iOrderByCol = j+1;
}
}
+12 -25
View File
@@ -21,7 +21,7 @@
/***/ int sqlite3SelectTrace = 0;
# define SELECTTRACE(K,P,S,X) \
if(sqlite3SelectTrace&(K)) \
sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->addrExplain,(S)),\
sqlite3DebugPrintf("%u/%d/%p: ",(S)->selId,(P)->addrExplain,(S)),\
sqlite3DebugPrintf X
#else
# define SELECTTRACE(K,P,S,X)
@@ -151,9 +151,7 @@ Select *sqlite3SelectNew(
pNew->selFlags = selFlags;
pNew->iLimit = 0;
pNew->iOffset = 0;
#if SELECTTRACE_ENABLED
pNew->zSelName[0] = 0;
#endif
pNew->selId = ++pParse->nSelect;
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
@@ -181,17 +179,6 @@ Select *sqlite3SelectNew(
return pNew;
}
#if SELECTTRACE_ENABLED
/*
** Set the name of a Select object
*/
void sqlite3SelectSetName(Select *p, const char *zName){
if( p && zName ){
sqlite3_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
}
}
#endif
/*
** Delete the given Select structure and all of its substructures.
@@ -3838,8 +3825,8 @@ static int flattenSubquery(
assert( (p->selFlags & SF_Recursive)==0 || pSub->pPrior==0 );
/***** If we reach this point, flattening is permitted. *****/
SELECTTRACE(1,pParse,p,("flatten %s.%p from term %d\n",
pSub->zSelName, pSub, iFrom));
SELECTTRACE(1,pParse,p,("flatten %u.%p from term %d\n",
pSub->selId, pSub, iFrom));
/* Authorize the subquery */
pParse->zAuthContext = pSubitem->zName;
@@ -3890,7 +3877,6 @@ static int flattenSubquery(
p->pPrior = 0;
p->pLimit = 0;
pNew = sqlite3SelectDup(db, p, 0);
sqlite3SelectSetName(pNew, pSub->zSelName);
p->pLimit = pLimit;
p->pOrderBy = pOrderBy;
p->pSrc = pSrc;
@@ -3903,7 +3889,7 @@ static int flattenSubquery(
pNew->pNext = p;
p->pPrior = pNew;
SELECTTRACE(2,pParse,p,("compound-subquery flattener"
" creates %s.%p as peer\n",pNew->zSelName, pNew));
" creates %u as peer\n",pNew->selId));
}
if( db->mallocFailed ) return 1;
}
@@ -4157,7 +4143,7 @@ static int pushDownWhereTerms(
if( pSubq->selFlags & SF_Recursive ) return 0; /* restriction (2) */
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pSubq->pWin ) return 0;
if( pSubq->pWin ) return 0; /* restriction (6) */
#endif
#ifdef SQLITE_DEBUG
@@ -4623,7 +4609,7 @@ int sqlite3ExpandSubquery(Parse *pParse, struct SrcList_item *pFrom){
if( pFrom->zAlias ){
pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias);
}else{
pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%p", (void*)pTab);
pTab->zName = sqlite3MPrintf(pParse->db, "subquery_%u", pSel->selId);
}
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
@@ -4729,7 +4715,6 @@ static int selectExpander(Walker *pWalker, Select *p){
if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort;
assert( pFrom->pSelect==0 );
pFrom->pSelect = sqlite3SelectDup(db, pTab->pSelect, 0);
sqlite3SelectSetName(pFrom->pSelect, pTab->zName);
nCol = pTab->nCol;
pTab->nCol = -1;
sqlite3WalkSelect(pWalker, pFrom->pSelect);
@@ -5187,7 +5172,7 @@ static void updateAccumulator(Parse *pParse, int regAcc, AggInfo *pAggInfo){
if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
}
sqlite3VdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, pF->iMem);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
sqlite3ExprCacheAffinityChange(pParse, regAgg, nArg);
@@ -5721,7 +5706,7 @@ int sqlite3Select(
VdbeComment((v, "%s", pItem->pTab->zName));
pItem->addrFillSub = addrTop;
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub));
ExplainQueryPlan((pParse, 1, "CO-ROUTINE %u", pSub->selId));
sqlite3Select(pParse, pSub, &dest);
pItem->pTab->nRowLogEst = pSub->nSelectRow;
pItem->fg.viaCoroutine = 1;
@@ -5760,7 +5745,7 @@ int sqlite3Select(
pSub->nSelectRow = pPrior->pSelect->nSelectRow;
}else{
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub));
ExplainQueryPlan((pParse, 1, "MATERIALIZE %u", pSub->selId));
sqlite3Select(pParse, pSub, &dest);
}
pItem->pTab->nRowLogEst = pSub->nSelectRow;
@@ -5940,9 +5925,11 @@ int sqlite3Select(
sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak);
sqlite3VdbeResolveLabel(v, addrGosub);
VdbeNoopComment((v, "inner-loop subroutine"));
selectInnerLoop(pParse, p, -1, &sSort, &sDistinct, pDest, iCont, iBreak);
sqlite3VdbeResolveLabel(v, iCont);
sqlite3VdbeAddOp1(v, OP_Return, regGosub);
VdbeComment((v, "end inner-loop subroutine"));
sqlite3VdbeResolveLabel(v, iBreak);
}else
#endif /* SQLITE_OMIT_WINDOWFUNC */
+6 -1
View File
@@ -4354,6 +4354,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
"SELECT total(length(sql)) FROM %s" },
};
int i;
unsigned iDataVersion;
char *zSchemaTab;
char *zDb = nArg>=2 ? azArg[1] : "main";
sqlite3_stmt *pStmt = 0;
@@ -4406,6 +4407,8 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
utf8_printf(p->out, "%-20s %d\n", aQuery[i].zName, val);
}
sqlite3_free(zSchemaTab);
sqlite3_file_control(p->db, zDb, SQLITE_FCNTL_DATA_VERSION, &iDataVersion);
utf8_printf(p->out, "%-20s %u\n", "data version", iDataVersion);
return 0;
}
@@ -5862,7 +5865,8 @@ static int do_meta_command(char *zLine, ShellState *p){
const char *zLike = 0;
int i;
int savedShowHeader = p->showHeader;
ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines);
int savedShellFlags = p->shellFlgs;
ShellClearFlag(p, SHFLG_PreserveRowid|SHFLG_Newlines|SHFLG_Echo);
for(i=1; i<nArg; i++){
if( azArg[i][0]=='-' ){
const char *z = azArg[i]+1;
@@ -5944,6 +5948,7 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
p->showHeader = savedShowHeader;
p->shellFlgs = savedShellFlags;
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
+61 -9
View File
@@ -1073,6 +1073,25 @@ struct sqlite3_io_methods {
** a file lock using the xLock or xShmLock methods of the VFS to wait
** for up to M milliseconds before failing, where M is the single
** unsigned integer parameter.
**
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
** a database file. The argument is a pointer to a 32-bit unsigned integer.
** The "data version" for the pager is written into the pointer. The
** "data version" changes whenever any change occurs to the corresponding
** database file, either through SQL statements on the same database
** connection, or through transactions committed by separate database
** connections possibly in other processes. The [sqlite3_total_changes()]
** interface can be used to find if any database on the connection has changed,
** but that interface response to changes on TEMP as well as MAIN and does
** not provide a mechanism to detect changes to MAIN only. Also, the
** [sqlite3_total_changes()] interface response to internal changes only and
** omits changes made by other database connections. The
** [PRAGMA data_version] command provide a mechanism to detect changes to
** a single attached database that occur due to other database connections,
** but omits changes implemented by the database connection for which it is
** called. This file control is the only mechanism to detect changes that
** happen either internally or externally on a single database.
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1108,6 +1127,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
#define SQLITE_FCNTL_LOCK_TIMEOUT 34
#define SQLITE_FCNTL_DATA_VERSION 35
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
@@ -2122,6 +2142,12 @@ struct sqlite3_mem_methods {
** with no schema and no content. The following process works even for
** a badly corrupted database file:
** <ol>
** <li> If the database connection is newly opened, make sure it has read the
** database schema by preparing then discarding some query against the
** database, or calling sqlite3_table_column_metadata(), ignoring any
** errors. This step is only necessary if the application desires to keep
** the database in WAL mode after the reset if it was in WAL mode before
** the reset.
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
@@ -2270,12 +2296,17 @@ void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
** program, the value returned reflects the number of rows modified by the
** previous INSERT, UPDATE or DELETE statement within the same trigger.
**
** See also the [sqlite3_total_changes()] interface, the
** [count_changes pragma], and the [changes() SQL function].
**
** If a separate thread makes changes on the same database connection
** while [sqlite3_changes()] is running then the value returned
** is unpredictable and not meaningful.
**
** See also:
** <ul>
** <li> the [sqlite3_total_changes()] interface
** <li> the [count_changes pragma]
** <li> the [changes() SQL function]
** <li> the [data_version pragma]
** </ul>
*/
int sqlite3_changes(sqlite3*);
@@ -2293,13 +2324,26 @@ int sqlite3_changes(sqlite3*);
** count, but those made as part of REPLACE constraint resolution are
** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
** are not counted.
**
** See also the [sqlite3_changes()] interface, the
** [count_changes pragma], and the [total_changes() SQL function].
**
** This the [sqlite3_total_changes(D)] interface only reports the number
** of rows that changed due to SQL statement run against database
** connection D. Any changes by other database connections are ignored.
** To detect changes against a database file from other database
** connections use the [PRAGMA data_version] command or the
** [SQLITE_FCNTL_DATA_VERSION] [file control].
**
** If a separate thread makes changes on the same database connection
** while [sqlite3_total_changes()] is running then the value
** returned is unpredictable and not meaningful.
**
** See also:
** <ul>
** <li> the [sqlite3_changes()] interface
** <li> the [count_changes pragma]
** <li> the [changes() SQL function]
** <li> the [data_version pragma]
** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
** </ul>
*/
int sqlite3_total_changes(sqlite3*);
@@ -7071,6 +7115,7 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
/*
** CAPI3REF: Low-Level Control Of Database Files
** METHOD: sqlite3
** KEYWORDS: {file control}
**
** ^The [sqlite3_file_control()] interface makes a direct call to the
** xFileControl method for the [sqlite3_io_methods] object associated
@@ -7085,11 +7130,18 @@ sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
** the xFileControl method. ^The return value of the xFileControl
** method becomes the return value of this routine.
**
** A few opcodes for [sqlite3_file_control()] are handled directly
** by the SQLite core and never invoke the
** sqlite3_io_methods.xFileControl method.
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
** a pointer to the underlying [sqlite3_file] object to be written into
** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
** case is a short-circuit path which does not actually invoke the
** underlying sqlite3_io_methods.xFileControl method.
** the space pointed to by the 4th parameter. The
** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
** the [sqlite3_file] object associated with the journal file instead of
** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns
** a pointer to the underlying [sqlite3_vfs] object for the file.
** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
** from the pager.
**
** ^If the second parameter (zDbName) does not match the name of any
** open database file, then SQLITE_ERROR is returned. ^This error
+29 -23
View File
@@ -1583,6 +1583,7 @@ struct sqlite3 {
/* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */
#define SQLITE_PushDown 0x1000 /* The push-down optimization */
#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */
#define SQLITE_SkipScan 0x4000 /* Skip-scans */
#define SQLITE_AllOpts 0xffff /* All optimizations */
/*
@@ -2808,9 +2809,7 @@ struct Select {
LogEst nSelectRow; /* Estimated number of result rows */
u32 selFlags; /* Various SF_* values */
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
#if SELECTTRACE_ENABLED
char zSelName[12]; /* Symbolic name of this SELECT use for debugging */
#endif
u32 selId; /* Unique identifier number for this SELECT */
int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
@@ -3071,9 +3070,7 @@ struct Parse {
int regRowid; /* Register holding rowid of CREATE TABLE entry */
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
#if SELECTTRACE_ENABLED
int nSelect; /* Number of SELECT statements seen */
#endif
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -3387,7 +3384,7 @@ struct Sqlite3Config {
/* The following callback (if not NULL) is invoked on every VDBE branch
** operation. Set the callback using SQLITE_TESTCTRL_VDBE_COVERAGE.
*/
void (*xVdbeBranch)(void*,int iSrcLine,u8 eThis,u8 eMx); /* Callback */
void (*xVdbeBranch)(void*,unsigned iSrcLine,u8 eThis,u8 eMx); /* Callback */
void *pVdbeBranchArg; /* 1st argument */
#endif
#ifndef SQLITE_UNTESTABLE
@@ -3490,8 +3487,22 @@ struct TreeView {
#endif /* SQLITE_DEBUG */
/*
** Object used to encode the OVER() clause attached to a window-function
** invocation. And some fields used while generating VM code for the same.
** This object is used in varioius ways, all related to window functions
**
** (1) A single instance of this structure is attached to the
** the Expr.pWin field for each window function in an expression tree.
** This object holds the information contained in the OVER clause,
** plus additional fields used during code generation.
**
** (2) All window functions in a single SELECT form a linked-list
** attached to Select.pWin. The Window.pFunc and Window.pExpr
** fields point back to the expression that is the window function.
**
** (3) The terms of the WINDOW clause of a SELECT are instances of this
** object on a linked list attached to Select.pWinDefn.
**
** The uses (1) and (2) are really the same Window object that just happens
** to be accessible in two different ways. Use (3) is are separate objects.
*/
struct Window {
char *zName; /* Name of window (may be NULL) */
@@ -3502,20 +3513,16 @@ struct Window {
u8 eEnd; /* UNBOUNDED, CURRENT, PRECEDING or FOLLOWING */
Expr *pStart; /* Expression for "<expr> PRECEDING" */
Expr *pEnd; /* Expression for "<expr> FOLLOWING" */
Window *pNextWin; /* Next window function belonging to this SELECT */
Expr *pFilter;
FuncDef *pFunc;
int iEphCsr; /* Temp table used by this window */
Expr *pFilter; /* The FILTER expression */
FuncDef *pFunc; /* The function */
int iEphCsr; /* Partition buffer or Peer buffer */
int regAccum;
int regResult;
int csrApp; /* Function cursor (used by min/max) */
int regApp; /* Function register (also used by min/max) */
int regPart;
int regPart; /* First in a set of registers holding PARTITION BY
** and ORDER BY values for the window */
Expr *pOwner; /* Expression object this window is attached to */
int nBufferCol; /* Number of columns in buffer table */
int iArgCol; /* Offset of first argument for this function */
@@ -3755,6 +3762,10 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
void sqlite3TreeViewExprList(TreeView*, const ExprList*, u8, const char*);
void sqlite3TreeViewSelect(TreeView*, const Select*, u8);
void sqlite3TreeViewWith(TreeView*, const With*, u8);
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3TreeViewWindow(TreeView*, const Window*, u8);
void sqlite3TreeViewWinFunc(TreeView*, const Window*, u8);
#endif
#endif
@@ -4010,11 +4021,6 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int);
SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int);
IdList *sqlite3IdListDup(sqlite3*,IdList*);
Select *sqlite3SelectDup(sqlite3*,Select*,int);
#if SELECTTRACE_ENABLED
void sqlite3SelectSetName(Select*,const char*);
#else
# define sqlite3SelectSetName(A,B)
#endif
void sqlite3InsertBuiltinFuncs(FuncDef*,int);
FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8);
void sqlite3RegisterBuiltinFunctions(void);
+40
View File
@@ -5684,6 +5684,44 @@ static int SQLITE_TCLAPI file_control_lasterrno_test(
return TCL_OK;
}
/*
** tclcmd: file_control_data_version DB DBNAME
**
** This TCL command runs the sqlite3_file_control with the
** SQLITE_FCNTL_DATA_VERSION opcode, returning the result.
*/
static int SQLITE_TCLAPI file_control_data_version(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
unsigned int iVers; /* data version */
char *zDb; /* Db name ("main", "temp" etc.) */
sqlite3 *db; /* Database handle */
int rc; /* file_control() return code */
char zBuf[100];
if( objc!=3 && objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers);
if( rc ){
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
return TCL_ERROR;
}else{
sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
return TCL_OK;
}
}
/*
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
**
@@ -6954,6 +6992,7 @@ static int SQLITE_TCLAPI optimization_control(
{ "omit-noop-join", SQLITE_OmitNoopJoin },
{ "stat3", SQLITE_Stat34 },
{ "stat4", SQLITE_Stat34 },
{ "skip-scan", SQLITE_SkipScan },
};
if( objc!=4 ){
@@ -7699,6 +7738,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
{ "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_data_version", file_control_data_version, 0 },
#if SQLITE_OS_WIN
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "file_control_win32_get_handle", file_control_win32_get_handle, 0 },
+30 -4
View File
@@ -133,8 +133,9 @@ struct Testvfs {
#define TESTVFS_UNLOCK_MASK 0x00020000
#define TESTVFS_LOCK_MASK 0x00040000
#define TESTVFS_CKLOCK_MASK 0x00080000
#define TESTVFS_FCNTL_MASK 0x00100000
#define TESTVFS_ALL_MASK 0x000FFFFF
#define TESTVFS_ALL_MASK 0x001FFFFF
#define TESTVFS_MAX_PAGES 1024
@@ -517,7 +518,8 @@ static int tvfsCheckReservedLock(sqlite3_file *pFile, int *pResOut){
** File control method. For custom operations on an tvfs-file.
*/
static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
TestvfsFd *p = tvfsGetFd(pFile);
TestvfsFd *pFd = tvfsGetFd(pFile);
Testvfs *p = (Testvfs *)pFd->pVfs->pAppData;
if( op==SQLITE_FCNTL_PRAGMA ){
char **argv = (char**)pArg;
if( sqlite3_stricmp(argv[1],"error")==0 ){
@@ -535,11 +537,34 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){
return rc;
}
if( sqlite3_stricmp(argv[1], "filename")==0 ){
argv[0] = sqlite3_mprintf("%s", p->zFilename);
argv[0] = sqlite3_mprintf("%s", pFd->zFilename);
return SQLITE_OK;
}
}
return sqlite3OsFileControl(p->pReal, op, pArg);
if( p->pScript && (p->mask&TESTVFS_FCNTL_MASK) ){
struct Fcntl {
int iFnctl;
const char *zFnctl;
} aF[] = {
{ SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, "BEGIN_ATOMIC_WRITE" },
{ SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, "COMMIT_ATOMIC_WRITE" },
};
int i;
for(i=0; i<sizeof(aF)/sizeof(aF[0]); i++){
if( op==aF[i].iFnctl ) break;
}
if( i<sizeof(aF)/sizeof(aF[0]) ){
int rc = 0;
tvfsExecTcl(p, "xFileControl",
Tcl_NewStringObj(pFd->zFilename, -1),
Tcl_NewStringObj(aF[i].zFnctl, -1),
0, 0
);
tvfsResultCode(p, &rc);
if( rc ) return rc;
}
}
return sqlite3OsFileControl(pFd->pReal, op, pArg);
}
/*
@@ -1160,6 +1185,7 @@ static int SQLITE_TCLAPI testvfs_obj_cmd(
{ "xUnlock", TESTVFS_UNLOCK_MASK },
{ "xLock", TESTVFS_LOCK_MASK },
{ "xCheckReservedLock", TESTVFS_CKLOCK_MASK },
{ "xFileControl", TESTVFS_FCNTL_MASK },
};
Tcl_Obj **apElem = 0;
int nElem = 0;
+27
View File
@@ -302,6 +302,32 @@ static int SQLITE_TCLAPI test_create_sumint(
return TCL_OK;
}
static int SQLITE_TCLAPI test_override_sum(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
int rc;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "sum", -1, SQLITE_UTF8, 0,
0, sumintStep, sumintFinal
);
if( rc!=SQLITE_OK ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
return TCL_ERROR;
}
return TCL_OK;
}
int Sqlitetest_window_Init(Tcl_Interp *interp){
static struct {
char *zName;
@@ -311,6 +337,7 @@ int Sqlitetest_window_Init(Tcl_Interp *interp){
{ "sqlite3_create_window_function", test_create_window, 0 },
{ "test_create_window_function_misuse", test_create_window_misuse, 0 },
{ "test_create_sumint", test_create_sumint, 0 },
{ "test_override_sum", test_override_sum, 0 },
};
int i;
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+3 -3
View File
@@ -264,7 +264,7 @@ static int analyzeFilterKeyword(const unsigned char *z, int lastToken){
}
return TK_ID;
}
#endif // SQLITE_OMIT_WINDOWFUNC
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Return the length (in bytes) of the token that begins at z[0].
@@ -604,7 +604,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
#else
if( tokenType>=TK_SPACE ){
assert( tokenType==TK_SPACE || tokenType==TK_ILLEGAL );
#endif // SQLITE_OMIT_WINDOWFUNC
#endif /* SQLITE_OMIT_WINDOWFUNC */
if( db->u1.isInterrupted ){
pParse->rc = SQLITE_INTERRUPT;
break;
@@ -634,7 +634,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
}else if( tokenType==TK_FILTER ){
assert( n==6 );
tokenType = analyzeFilterKeyword((const u8*)&zSql[6], lastTokenParsed);
#endif // SQLITE_OMIT_WINDOWFUNC
#endif /* SQLITE_OMIT_WINDOWFUNC */
}else{
sqlite3ErrorMsg(pParse, "unrecognized token: \"%.*s\"", n, zSql);
break;
+117 -11
View File
@@ -139,21 +139,13 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewPush(pView, 1);
}
do{
#if SELECTTRACE_ENABLED
sqlite3TreeViewLine(pView,
"SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d",
"SELECT%s%s (%u/%p) selFlags=0x%x nSelectRow=%d",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""),
p->zSelName, p, p->selFlags,
p->selId, p, p->selFlags,
(int)p->nSelectRow
);
#else
sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d",
((p->selFlags & SF_Distinct) ? " DISTINCT" : ""),
((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags,
(int)p->nSelectRow
);
#endif
if( cnt++ ) sqlite3TreeViewPop(pView);
if( p->pPrior ){
n = 1000;
@@ -165,8 +157,23 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
if( p->pHaving ) n++;
if( p->pOrderBy ) n++;
if( p->pLimit ) n++;
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWin ) n++;
if( p->pWinDefn ) n++;
#endif
}
sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set");
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWin ){
Window *pX;
pView = sqlite3TreeViewPush(pView, (n--)>0);
sqlite3TreeViewLine(pView, "window-functions");
for(pX=p->pWin; pX; pX=pX->pNextWin){
sqlite3TreeViewWinFunc(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
}
#endif
if( p->pSrc && p->pSrc->nSrc ){
int i;
pView = sqlite3TreeViewPush(pView, (n--)>0);
@@ -216,6 +223,16 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewExpr(pView, p->pHaving, 0);
sqlite3TreeViewPop(pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( p->pWinDefn ){
Window *pX;
sqlite3TreeViewItem(pView, "WINDOW", (n--)>0);
for(pX=p->pWinDefn; pX; pX=pX->pNextWin){
sqlite3TreeViewWindow(pView, pX, pX->pNextWin!=0);
}
sqlite3TreeViewPop(pView);
}
#endif
if( p->pOrderBy ){
sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY");
}
@@ -243,6 +260,83 @@ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){
sqlite3TreeViewPop(pView);
}
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a description of starting or stopping bounds
*/
void sqlite3TreeViewBound(
TreeView *pView, /* View context */
u8 eBound, /* UNBOUNDED, CURRENT, PRECEDING, FOLLOWING */
Expr *pExpr, /* Value for PRECEDING or FOLLOWING */
u8 moreToFollow /* True if more to follow */
){
switch( eBound ){
case TK_UNBOUNDED: {
sqlite3TreeViewItem(pView, "UNBOUNDED", moreToFollow);
sqlite3TreeViewPop(pView);
break;
}
case TK_CURRENT: {
sqlite3TreeViewItem(pView, "CURRENT", moreToFollow);
sqlite3TreeViewPop(pView);
break;
}
case TK_PRECEDING: {
sqlite3TreeViewItem(pView, "PRECEDING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
break;
}
case TK_FOLLOWING: {
sqlite3TreeViewItem(pView, "FOLLOWING", moreToFollow);
sqlite3TreeViewExpr(pView, pExpr, 0);
sqlite3TreeViewPop(pView);
break;
}
}
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a human-readable explanation for a Window object
*/
void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u8 more){
pView = sqlite3TreeViewPush(pView, more);
if( pWin->zName ){
sqlite3TreeViewLine(pView, "OVER %s", pWin->zName);
}else{
sqlite3TreeViewLine(pView, "OVER");
}
if( pWin->pPartition ){
sqlite3TreeViewExprList(pView, pWin->pPartition, 1, "PARTITION-BY");
}
if( pWin->pOrderBy ){
sqlite3TreeViewExprList(pView, pWin->pOrderBy, 1, "ORDER-BY");
}
if( pWin->eType ){
sqlite3TreeViewItem(pView, pWin->eType==TK_RANGE ? "RANGE" : "ROWS", 0);
sqlite3TreeViewBound(pView, pWin->eStart, pWin->pStart, 1);
sqlite3TreeViewBound(pView, pWin->eEnd, pWin->pEnd, 0);
sqlite3TreeViewPop(pView);
}
sqlite3TreeViewPop(pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
#ifndef SQLITE_OMIT_WINDOWFUNC
/*
** Generate a human-readable explanation for a Window Function object
*/
void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){
pView = sqlite3TreeViewPush(pView, more);
sqlite3TreeViewLine(pView, "WINFUNC %s(%d)",
pWin->pFunc->zName, pWin->pFunc->nArg);
sqlite3TreeViewWindow(pView, pWin, 0);
sqlite3TreeViewPop(pView);
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** Generate a human-readable explanation of an expression tree.
*/
@@ -393,10 +487,17 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
case TK_AGG_FUNCTION:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
Window *pWin;
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
pWin = 0;
}else{
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
pWin = pExpr->pWin;
#else
pWin = 0;
#endif
}
if( pExpr->op==TK_AGG_FUNCTION ){
sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q",
@@ -405,8 +506,13 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken);
}
if( pFarg ){
sqlite3TreeViewExprList(pView, pFarg, 0, 0);
sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
}
#ifndef SQLITe_OMIT_WINDOWFUNC
if( pWin ){
sqlite3TreeViewWindow(pView, pWin, 0);
}
#endif
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
+1 -1
View File
@@ -523,7 +523,7 @@ void sqlite3Update(
if( !isView && aiCurOnePass[0]!=iDataCur && aiCurOnePass[1]!=iDataCur ){
assert( pPk );
sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey,nKey);
VdbeCoverageNeverTaken(v);
VdbeCoverage(v);
}
if( eOnePass!=ONEPASS_SINGLE ){
labelContinue = sqlite3VdbeMakeLabel(v);
+103 -34
View File
@@ -134,32 +134,56 @@ int sqlite3_found_count = 0;
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is an integer, 2 or 3, that indices how many different ways the
** branch can go. It is usually 2. "I" is the direction the branch
** goes. 0 means falls through. 1 means branch is taken. 2 means the
** second alternative branch is taken.
** M is an integer between 2 and 4. 2 indicates a ordinary two-way
** branch (I=0 means fall through and I=1 means taken). 3 indicates
** a 3-way branch where the third way is when one of the operands is
** NULL. 4 indicates the OP_Jump instruction which has three destinations
** depending on whether the first operand is less than, equal to, or greater
** than the second.
**
** iSrcLine is the source code line (from the __LINE__ macro) that
** generated the VDBE instruction. This instrumentation assumes that all
** source code is in a single file (the amalgamation). Special values 1
** and 2 for the iSrcLine parameter mean that this particular branch is
** always taken or never taken, respectively.
** generated the VDBE instruction combined with flag bits. The source
** code line number is in the lower 24 bits of iSrcLine and the upper
** 8 bytes are flags. The lower three bits of the flags indicate
** values for I that should never occur. For example, if the branch is
** always taken, the flags should be 0x05 since the fall-through and
** alternate branch are never taken. If a branch is never taken then
** flags should be 0x06 since only the fall-through approach is allowed.
**
** Bit 0x04 of the flags indicates an OP_Jump opcode that is only
** interested in equal or not-equal. In other words, I==0 and I==2
** should be treated the same.
**
** Since only a line number is retained, not the filename, this macro
** only works for amalgamation builds. But that is ok, since these macros
** should be no-ops except for special builds used to measure test coverage.
*/
#if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M)
#else
# define VdbeBranchTaken(I,M) vdbeTakeBranch(pOp->iSrcLine,I,M)
static void vdbeTakeBranch(int iSrcLine, u8 I, u8 M){
if( iSrcLine<=2 && ALWAYS(iSrcLine>0) ){
M = iSrcLine;
/* Assert the truth of VdbeCoverageAlwaysTaken() and
** VdbeCoverageNeverTaken() */
assert( (M & I)==I );
}else{
if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
iSrcLine,I,M);
static void vdbeTakeBranch(u32 iSrcLine, u8 I, u8 M){
u8 mNever;
assert( I<=2 ); /* 0: fall through, 1: taken, 2: alternate taken */
assert( M<=4 ); /* 2: two-way branch, 3: three-way branch, 4: OP_Jump */
assert( I<M ); /* I can only be 2 if M is 3 or 4 */
/* Transform I from a integer [0,1,2] into a bitmask of [1,2,4] */
I = 1<<I;
/* The upper 8 bits of iSrcLine are flags. The lower three bits of
** the flags indicate directions that the branch can never go. If
** a branch really does go in one of those directions, assert right
** away. */
mNever = iSrcLine >> 24;
assert( (I & mNever)==0 );
if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
I |= mNever;
if( M==2 ) I |= 0x04;
if( M==4 ){
I |= 0x08;
if( (mNever&0x08)!=0 && (I&0x05)!=0) I |= 0x05; /*NO_TEST*/
}
sqlite3GlobalConfig.xVdbeBranch(sqlite3GlobalConfig.pVdbeBranchArg,
iSrcLine&0xffffff, I, M);
}
#endif
@@ -1155,6 +1179,9 @@ case OP_Null: { /* out2 */
assert( pOp->p3<=(p->nMem+1 - p->nCursor) );
pOut->flags = nullFlag = pOp->p1 ? (MEM_Null|MEM_Cleared) : MEM_Null;
pOut->n = 0;
#ifdef SQLITE_DEBUG
pOut->uTemp = 0;
#endif
while( cnt>0 ){
pOut++;
memAboutToChange(p, pOut);
@@ -2159,11 +2186,11 @@ case OP_Compare: {
*/
case OP_Jump: { /* jump */
if( iCompare<0 ){
VdbeBranchTaken(0,3); pOp = &aOp[pOp->p1 - 1];
VdbeBranchTaken(0,4); pOp = &aOp[pOp->p1 - 1];
}else if( iCompare==0 ){
VdbeBranchTaken(1,3); pOp = &aOp[pOp->p2 - 1];
VdbeBranchTaken(1,4); pOp = &aOp[pOp->p2 - 1];
}else{
VdbeBranchTaken(2,3); pOp = &aOp[pOp->p3 - 1];
VdbeBranchTaken(2,4); pOp = &aOp[pOp->p3 - 1];
}
break;
}
@@ -6288,18 +6315,29 @@ case OP_DecrJumpZero: { /* jump, in1 */
}
/* Opcode: AggStep0 P1 P2 P3 P4 P5
/* Opcode: AggStep * P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
** aggregate. The function has P5 arguments. P4 is a pointer to the
** Execute the xStep function for an aggregate.
** The function has P5 arguments. P4 is a pointer to the
** FuncDef structure that specifies the function. Register P3 is the
** accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
*/
/* Opcode: AggStep P1 P2 P3 P4 P5
/* Opcode: AggInverse * P2 P3 P4 P5
** Synopsis: accum=r[P3] inverse(r[P2@P5])
**
** Execute the xInverse function for an aggregate.
** The function has P5 arguments. P4 is a pointer to the
** FuncDef structure that specifies the function. Register P3 is the
** accumulator.
**
** The P5 arguments are taken from register P2 and its
** successors.
*/
/* Opcode: AggStep1 P1 P2 P3 P4 P5
** Synopsis: accum=r[P3] step(r[P2@P5])
**
** Execute the xStep (if P1==0) or xInverse (if P1!=0) function for an
@@ -6316,7 +6354,8 @@ case OP_DecrJumpZero: { /* jump, in1 */
** sqlite3_context only happens once, instead of on each call to the
** step function.
*/
case OP_AggStep0: {
case OP_AggInverse:
case OP_AggStep: {
int n;
sqlite3_context *pCtx;
@@ -6339,10 +6378,14 @@ case OP_AggStep0: {
pCtx->argc = n;
pOp->p4type = P4_FUNCCTX;
pOp->p4.pCtx = pCtx;
pOp->opcode = OP_AggStep;
/* OP_AggInverse must have P1==1 and OP_AggStep must have P1==0 */
assert( pOp->p1==(pOp->opcode==OP_AggInverse) );
pOp->opcode = OP_AggStep1;
/* Fall through into OP_AggStep */
}
case OP_AggStep: {
case OP_AggStep1: {
int i;
sqlite3_context *pCtx;
Mem *pMem;
@@ -6351,6 +6394,17 @@ case OP_AggStep: {
pCtx = pOp->p4.pCtx;
pMem = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
if( pOp->p1 ){
/* This is an OP_AggInverse call. Verify that xStep has always
** been called at least once prior to any xInverse call. */
assert( pMem->uTemp==0x1122e0e3 );
}else{
/* This is an OP_AggStep call. Mark it as such. */
pMem->uTemp = 0x1122e0e3;
}
#endif
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
@@ -6399,24 +6453,37 @@ case OP_AggStep: {
break;
}
/* Opcode: AggFinal P1 P2 P3 P4 *
/* Opcode: AggFinal P1 P2 * P4 *
** Synopsis: accum=r[P1] N=P2
**
** P1 is the memory location that is the accumulator for an aggregate
** or window function. If P3 is zero, then execute the finalizer function
** for an aggregate and store the result in P1. Or, if P3 is non-zero,
** invoke the xValue() function and store the result in register P3.
** or window function. Execute the finalizer function
** for an aggregate and store the result in P1.
**
** P2 is the number of arguments that the step function takes and
** P4 is a pointer to the FuncDef for this function. The P2
** argument is not used by this opcode. It is only there to disambiguate
** functions that can take varying numbers of arguments. The
** P4 argument is only needed for the degenerate case where
** P4 argument is only needed for the case where
** the step function was not previously called.
*/
/* Opcode: AggValue * P2 P3 P4 *
** Synopsis: r[P3]=value N=P2
**
** Invoke the xValue() function and store the result in register P3.
**
** P2 is the number of arguments that the step function takes and
** P4 is a pointer to the FuncDef for this function. The P2
** argument is not used by this opcode. It is only there to disambiguate
** functions that can take varying numbers of arguments. The
** P4 argument is only needed for the case where
** the step function was not previously called.
*/
case OP_AggValue:
case OP_AggFinal: {
Mem *pMem;
assert( pOp->p1>0 && pOp->p1<=(p->nMem+1 - p->nCursor) );
assert( pOp->p3==0 || pOp->opcode==OP_AggValue );
pMem = &aMem[pOp->p1];
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
#ifndef SQLITE_OMIT_WINDOWFUNC
@@ -6425,7 +6492,9 @@ case OP_AggFinal: {
pMem = &aMem[pOp->p3];
}else
#endif
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
{
rc = sqlite3VdbeMemFinalize(pMem, pOp->p4.pFunc);
}
if( rc ){
sqlite3VdbeError(p, "%s", sqlite3_value_text(pMem));
+33 -4
View File
@@ -73,7 +73,8 @@ struct VdbeOp {
u64 cycles; /* Total time spent executing this instruction */
#endif
#ifdef SQLITE_VDBE_COVERAGE
int iSrcLine; /* Source-code line that generated this opcode */
u32 iSrcLine; /* Source-code line that generated this opcode
** with flags in the upper 8 bits */
#endif
};
typedef struct VdbeOp VdbeOp;
@@ -243,7 +244,6 @@ void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);
#ifdef SQLITE_DEBUG
int sqlite3VdbeAssertMayAbort(Vdbe *, int);
int sqlite3VdbeAssertAggContext(sqlite3_context*);
#endif
void sqlite3VdbeResetStepResult(Vdbe*);
void sqlite3VdbeRewind(Vdbe*);
@@ -318,23 +318,52 @@ int sqlite3NotPureFunc(sqlite3_context*);
**
** VdbeCoverageNeverTaken(v) // Previous branch is never taken
**
** VdbeCoverageNeverNull(v) // Previous three-way branch is only
** // taken on the first two ways. The
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
** // in distingishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
** -DSQLITE_DEBUG then an ALWAYS() will fail in the vdbeTakeBranch()
** routine in vdbe.c, alerting the developer to the missed tag.
**
** During testing, the test application will invoke
** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
** contains the sqlite3.c source line number ov the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
**
** See the VdbeBranchTaken() macro and vdbeTakeBranch() function in the
** vdbe.c source file for additional information.
*/
#ifdef SQLITE_VDBE_COVERAGE
void sqlite3VdbeSetLineNumber(Vdbe*,int);
# define VdbeCoverage(v) sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageIf(v,x) if(x)sqlite3VdbeSetLineNumber(v,__LINE__)
# define VdbeCoverageAlwaysTaken(v) sqlite3VdbeSetLineNumber(v,2);
# define VdbeCoverageNeverTaken(v) sqlite3VdbeSetLineNumber(v,1);
# define VdbeCoverageAlwaysTaken(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x5000000);
# define VdbeCoverageNeverTaken(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x6000000);
# define VdbeCoverageNeverNull(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
# define VdbeCoverageNeverNullIf(v,x) \
if(x)sqlite3VdbeSetLineNumber(v,__LINE__|0x4000000);
# define VdbeCoverageEqNe(v) \
sqlite3VdbeSetLineNumber(v,__LINE__|0x8000000);
# define VDBE_OFFSET_LINENO(x) (__LINE__+x)
#else
# define VdbeCoverage(v)
# define VdbeCoverageIf(v,x)
# define VdbeCoverageAlwaysTaken(v)
# define VdbeCoverageNeverTaken(v)
# define VdbeCoverageNeverNull(v)
# define VdbeCoverageNeverNullIf(v,x)
# define VdbeCoverageEqNe(v)
# define VDBE_OFFSET_LINENO(x) 0
#endif
-12
View File
@@ -824,18 +824,6 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
}
}
/*
** This function is only used within assert() statements to check that the
** aggregate context has already been allocated. i.e.:
**
** assert( sqlite3VdbeAssertAggContext(p) );
*/
#ifdef SQLITE_DEBUG
int sqlite3VdbeAssertAggContext(sqlite3_context *p){
return ((p->pMem->flags & MEM_Agg)!=0);
}
#endif /* SQLITE_DEBUG */
/*
** Return the auxiliary data pointer, if any, for the iArg'th argument to
** the user-function defined by pCtx.
+1
View File
@@ -435,6 +435,7 @@ int sqlite3VdbeMemAggValue(Mem *pAccum, Mem *pOut, FuncDef *pFunc){
memset(&t, 0, sizeof(t));
t.flags = MEM_Null;
t.db = pAccum->db;
sqlite3VdbeMemSetNull(pOut);
ctx.pOut = pOut;
ctx.pMem = pAccum;
ctx.pFunc = pFunc;
+2 -1
View File
@@ -810,7 +810,7 @@ static void constructAutomaticIndex(
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -2672,6 +2672,7 @@ static int whereLoopAddBtreeIndex(
if( saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->noSkipScan==0
&& OptimizationEnabled(db, SQLITE_SkipScan)
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
){
+2 -2
View File
@@ -150,7 +150,7 @@ int sqlite3WhereExplainOneScan(
sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH);
sqlite3_str_appendall(&str, isSearch ? "SEARCH" : "SCAN");
if( pItem->pSelect ){
sqlite3_str_appendf(&str, " SUBQUERY 0x%p", pItem->pSelect);
sqlite3_str_appendf(&str, " SUBQUERY %u", pItem->pSelect->selId);
}else{
sqlite3_str_appendf(&str, " TABLE %s", pItem->zName);
}
@@ -1242,7 +1242,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
VdbeCoverage(v);
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
pLevel->op = OP_Goto;
}else
+6 -4
View File
@@ -256,11 +256,13 @@ static int isLikeOrGlob(
/* The optimization is possible only if (1) the pattern does not begin
** with a wildcard and if (2) the non-wildcard prefix does not end with
** an (illegal 0xff) character. The second condition is necessary so
** an (illegal 0xff) character, or (3) the pattern does not consist of
** a single escape character. The second condition is necessary so
** that we can increment the prefix key to find an upper bound for the
** range search.
*/
if( cnt!=0 && 255!=(u8)z[cnt-1] ){
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
+304 -170
View File
@@ -151,12 +151,8 @@ static void row_numberStepFunc(
){
i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ) (*p)++;
}
static void row_numberInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(apArg);
}
static void row_numberValueFunc(sqlite3_context *pCtx){
i64 *p = (i64*)sqlite3_aggregate_context(pCtx, sizeof(*p));
@@ -187,12 +183,8 @@ static void dense_rankStepFunc(
struct CallCount *p;
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ) p->nStep = 1;
}
static void dense_rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(apArg);
}
static void dense_rankValueFunc(sqlite3_context *pCtx){
struct CallCount *p;
@@ -225,12 +217,8 @@ static void rankStepFunc(
p->nValue = p->nStep;
}
}
}
static void rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(apArg);
}
static void rankValueFunc(sqlite3_context *pCtx){
struct CallCount *p;
@@ -253,11 +241,10 @@ static void percent_rankStepFunc(
sqlite3_value **apArg
){
struct CallCount *p;
assert( nArg==1 );
UNUSED_PARAMETER(nArg); assert( nArg==1 );
assert( sqlite3VdbeAssertAggContext(pCtx) );
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( ALWAYS(p) ){
if( p ){
if( p->nTotal==0 ){
p->nTotal = sqlite3_value_int64(apArg[0]);
}
@@ -267,12 +254,6 @@ static void percent_rankStepFunc(
}
}
}
static void percent_rankInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
}
static void percent_rankValueFunc(sqlite3_context *pCtx){
struct CallCount *p;
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
@@ -299,23 +280,16 @@ static void cume_distStepFunc(
sqlite3_value **apArg
){
struct CallCount *p;
assert( nArg==1 );
assert( nArg==1 ); UNUSED_PARAMETER(nArg);
assert( sqlite3VdbeAssertAggContext(pCtx) );
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( ALWAYS(p) ){
if( p ){
if( p->nTotal==0 ){
p->nTotal = sqlite3_value_int64(apArg[0]);
}
p->nStep++;
}
}
static void cume_distInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
}
static void cume_distValueFunc(sqlite3_context *pCtx){
struct CallCount *p;
p = (struct CallCount*)sqlite3_aggregate_context(pCtx, sizeof(*p));
@@ -346,7 +320,7 @@ static void ntileStepFunc(
sqlite3_value **apArg
){
struct NtileCtx *p;
assert( nArg==2 );
assert( nArg==2 ); UNUSED_PARAMETER(nArg);
p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ){
if( p->nTotal==0 ){
@@ -361,12 +335,6 @@ static void ntileStepFunc(
p->iRow++;
}
}
static void ntileInvFunc(
sqlite3_context *pCtx,
int nArg,
sqlite3_value **apArg
){
}
static void ntileValueFunc(sqlite3_context *pCtx){
struct NtileCtx *p;
p = (struct NtileCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
@@ -407,6 +375,7 @@ static void last_valueStepFunc(
sqlite3_value **apArg
){
struct LastValueCtx *p;
UNUSED_PARAMETER(nArg);
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( p ){
sqlite3_value_free(p->pVal);
@@ -424,6 +393,8 @@ static void last_valueInvFunc(
sqlite3_value **apArg
){
struct LastValueCtx *p;
UNUSED_PARAMETER(nArg);
UNUSED_PARAMETER(apArg);
p = (struct LastValueCtx*)sqlite3_aggregate_context(pCtx, sizeof(*p));
if( ALWAYS(p) ){
p->nVal--;
@@ -451,50 +422,92 @@ static void last_valueFinalizeFunc(sqlite3_context *pCtx){
}
/*
** No-op implementations of nth_value(), first_value(), lead() and lag().
** These are all implemented inline using VDBE instructions.
** Static names for the built-in window function names. These static
** names are used, rather than string literals, so that FuncDef objects
** can be associated with a particular window function by direct
** comparison of the zName pointer. Example:
**
** if( pFuncDef->zName==row_valueName ){ ... }
*/
static void nth_valueStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **a){}
static void nth_valueInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
static void nth_valueValueFunc(sqlite3_context *pCtx){}
static void first_valueStepFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
static void first_valueInvFunc(sqlite3_context *p, int n, sqlite3_value **ap){}
static void first_valueValueFunc(sqlite3_context *pCtx){}
static void leadStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
static void leadInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
static void leadValueFunc(sqlite3_context *pCtx){}
static void lagStepFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
static void lagInvFunc(sqlite3_context *pCtx, int n, sqlite3_value **ap){}
static void lagValueFunc(sqlite3_context *pCtx){}
static const char row_numberName[] = "row_number";
static const char dense_rankName[] = "dense_rank";
static const char rankName[] = "rank";
static const char percent_rankName[] = "percent_rank";
static const char cume_distName[] = "cume_dist";
static const char ntileName[] = "ntile";
static const char last_valueName[] = "last_value";
static const char nth_valueName[] = "nth_value";
static const char first_valueName[] = "first_value";
static const char leadName[] = "lead";
static const char lagName[] = "lag";
#define WINDOWFUNC(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
name ## InvFunc, #name \
}
/*
** No-op implementations of xStep() and xFinalize(). Used as place-holders
** for built-in window functions that never call those interfaces.
**
** The noopValueFunc() is called but is expected to do nothing. The
** noopStepFunc() is never called, and so it is marked with NO_TEST to
** let the test coverage routine know not to expect this function to be
** invoked.
*/
static void noopStepFunc( /*NO_TEST*/
sqlite3_context *p, /*NO_TEST*/
int n, /*NO_TEST*/
sqlite3_value **a /*NO_TEST*/
){ /*NO_TEST*/
UNUSED_PARAMETER(p); /*NO_TEST*/
UNUSED_PARAMETER(n); /*NO_TEST*/
UNUSED_PARAMETER(a); /*NO_TEST*/
assert(0); /*NO_TEST*/
} /*NO_TEST*/
static void noopValueFunc(sqlite3_context *p){ UNUSED_PARAMETER(p); /*no-op*/ }
#define WINDOWFUNCF(name,nArg,extra) { \
/* Window functions that use all window interfaces: xStep, xFinal,
** xValue, and xInverse */
#define WINDOWFUNCALL(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
name ## StepFunc, name ## FinalizeFunc, name ## ValueFunc, \
name ## InvFunc, #name \
name ## InvFunc, name ## Name, {0} \
}
/* Window functions that are implemented using bytecode and thus have
** no-op routines for their methods */
#define WINDOWFUNCNOOP(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
noopStepFunc, noopValueFunc, noopValueFunc, \
noopStepFunc, name ## Name, {0} \
}
/* Window functions that use all window interfaces: xStep, the
** same routine for xFinalize and xValue and which never call
** xInverse. */
#define WINDOWFUNCX(name,nArg,extra) { \
nArg, (SQLITE_UTF8|SQLITE_FUNC_WINDOW|extra), 0, 0, \
name ## StepFunc, name ## ValueFunc, name ## ValueFunc, \
noopStepFunc, name ## Name, {0} \
}
/*
** Register those built-in window functions that are not also aggregates.
*/
void sqlite3WindowFunctions(void){
static FuncDef aWindowFuncs[] = {
WINDOWFUNC(row_number, 0, 0),
WINDOWFUNC(dense_rank, 0, 0),
WINDOWFUNC(rank, 0, 0),
WINDOWFUNC(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNC(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNC(ntile, 1, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNCF(last_value, 1, 0),
WINDOWFUNC(nth_value, 2, 0),
WINDOWFUNC(first_value, 1, 0),
WINDOWFUNC(lead, 1, 0), WINDOWFUNC(lead, 2, 0), WINDOWFUNC(lead, 3, 0),
WINDOWFUNC(lag, 1, 0), WINDOWFUNC(lag, 2, 0), WINDOWFUNC(lag, 3, 0),
WINDOWFUNCX(row_number, 0, 0),
WINDOWFUNCX(dense_rank, 0, 0),
WINDOWFUNCX(rank, 0, 0),
WINDOWFUNCX(percent_rank, 0, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNCX(cume_dist, 0, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNCX(ntile, 1, SQLITE_FUNC_WINDOW_SIZE),
WINDOWFUNCALL(last_value, 1, 0),
WINDOWFUNCNOOP(nth_value, 2, 0),
WINDOWFUNCNOOP(first_value, 1, 0),
WINDOWFUNCNOOP(lead, 1, 0),
WINDOWFUNCNOOP(lead, 2, 0),
WINDOWFUNCNOOP(lead, 3, 0),
WINDOWFUNCNOOP(lag, 1, 0),
WINDOWFUNCNOOP(lag, 2, 0),
WINDOWFUNCNOOP(lag, 3, 0),
};
sqlite3InsertBuiltinFuncs(aWindowFuncs, ArraySize(aWindowFuncs));
}
@@ -546,7 +559,7 @@ void sqlite3WindowUpdate(
"FILTER clause may only be used with aggregate window functions"
);
}else
if( pFunc->xSFunc==row_numberStepFunc || pFunc->xSFunc==ntileStepFunc ){
if( pFunc->zName==row_numberName || pFunc->zName==ntileName ){
sqlite3ExprDelete(db, pWin->pStart);
sqlite3ExprDelete(db, pWin->pEnd);
pWin->pStart = pWin->pEnd = 0;
@@ -555,8 +568,8 @@ void sqlite3WindowUpdate(
pWin->eEnd = TK_CURRENT;
}else
if( pFunc->xSFunc==dense_rankStepFunc || pFunc->xSFunc==rankStepFunc
|| pFunc->xSFunc==percent_rankStepFunc || pFunc->xSFunc==cume_distStepFunc
if( pFunc->zName==dense_rankName || pFunc->zName==rankName
|| pFunc->zName==percent_rankName || pFunc->zName==cume_distName
){
sqlite3ExprDelete(db, pWin->pStart);
sqlite3ExprDelete(db, pWin->pEnd);
@@ -576,7 +589,9 @@ void sqlite3WindowUpdate(
typedef struct WindowRewrite WindowRewrite;
struct WindowRewrite {
Window *pWin;
SrcList *pSrc;
ExprList *pSub;
Select *pSubSelect; /* Current sub-select, if any */
};
/*
@@ -588,6 +603,24 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
struct WindowRewrite *p = pWalker->u.pRewrite;
Parse *pParse = pWalker->pParse;
/* If this function is being called from within a scalar sub-select
** that used by the SELECT statement being processed, only process
** TK_COLUMN expressions that refer to it (the outer SELECT). Do
** not process aggregates or window functions at all, as they belong
** to the scalar sub-select. */
if( p->pSubSelect ){
if( pExpr->op!=TK_COLUMN ){
return WRC_Continue;
}else{
int nSrc = p->pSrc->nSrc;
int i;
for(i=0; i<nSrc; i++){
if( pExpr->iTable==p->pSrc->a[i].iCursor ) break;
}
if( i==nSrc ) return WRC_Continue;
}
}
switch( pExpr->op ){
case TK_FUNCTION:
@@ -630,6 +663,15 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
struct WindowRewrite *p = pWalker->u.pRewrite;
Select *pSave = p->pSubSelect;
if( pSave==pSelect ){
return WRC_Continue;
}else{
p->pSubSelect = pSelect;
sqlite3WalkSelect(pWalker, pSelect);
p->pSubSelect = pSave;
}
return WRC_Prune;
}
@@ -640,7 +682,7 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
** * TK_COLUMN,
** * aggregate function, or
** * window function with a Window object that is not a member of the
** linked list passed as the second argument (pWin)
** Window list passed as the second argument (pWin).
**
** Append the node to output expression-list (*ppSub). And replace it
** with a TK_COLUMN that reads the (N-1)th element of table
@@ -650,6 +692,7 @@ static int selectWindowRewriteSelectCb(Walker *pWalker, Select *pSelect){
static void selectWindowRewriteEList(
Parse *pParse,
Window *pWin,
SrcList *pSrc,
ExprList *pEList, /* Rewrite expressions in this list */
ExprList **ppSub /* IN/OUT: Sub-select expression-list */
){
@@ -661,6 +704,7 @@ static void selectWindowRewriteEList(
sRewrite.pSub = *ppSub;
sRewrite.pWin = pWin;
sRewrite.pSrc = pSrc;
sWalker.pParse = pParse;
sWalker.xExprCallback = selectWindowRewriteExprCb;
@@ -738,8 +782,8 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){
** many columns the table will have. */
pMWin->iEphCsr = pParse->nTab++;
selectWindowRewriteEList(pParse, pMWin, p->pEList, &pSublist);
selectWindowRewriteEList(pParse, pMWin, p->pOrderBy, &pSublist);
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pEList, &pSublist);
selectWindowRewriteEList(pParse, pMWin, pSrc, p->pOrderBy, &pSublist);
pMWin->nBufferCol = (pSublist ? pSublist->nExpr : 0);
/* Append the PARTITION BY and ORDER BY expressions to the to the
@@ -829,29 +873,85 @@ void sqlite3WindowListDelete(sqlite3 *db, Window *p){
}
/*
** Allocate and return a new Window object.
** The argument expression is an PRECEDING or FOLLOWING offset. The
** value should be a non-negative integer. If the value is not a
** constant, change it to NULL. The fact that it is then a non-negative
** integer will be caught later. But it is important not to leave
** variable values in the expression tree.
*/
static Expr *sqlite3WindowOffsetExpr(Parse *pParse, Expr *pExpr){
if( 0==sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprDelete(pParse->db, pExpr);
pExpr = sqlite3ExprAlloc(pParse->db, TK_NULL, 0, 0);
}
return pExpr;
}
/*
** Allocate and return a new Window object describing a Window Definition.
*/
Window *sqlite3WindowAlloc(
Parse *pParse,
int eType,
int eStart, Expr *pStart,
int eEnd, Expr *pEnd
Parse *pParse, /* Parsing context */
int eType, /* Frame type. TK_RANGE or TK_ROWS */
int eStart, /* Start type: CURRENT, PRECEDING, FOLLOWING, UNBOUNDED */
Expr *pStart, /* Start window size if TK_PRECEDING or FOLLOWING */
int eEnd, /* End type: CURRENT, FOLLOWING, TK_UNBOUNDED, PRECEDING */
Expr *pEnd /* End window size if TK_FOLLOWING or PRECEDING */
){
Window *pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
Window *pWin = 0;
if( pWin ){
assert( eType );
pWin->eType = eType;
pWin->eStart = eStart;
pWin->eEnd = eEnd;
pWin->pEnd = pEnd;
pWin->pStart = pStart;
}else{
sqlite3ExprDelete(pParse->db, pEnd);
sqlite3ExprDelete(pParse->db, pStart);
/* Parser assures the following: */
assert( eType==TK_RANGE || eType==TK_ROWS );
assert( eStart==TK_CURRENT || eStart==TK_PRECEDING
|| eStart==TK_UNBOUNDED || eStart==TK_FOLLOWING );
assert( eEnd==TK_CURRENT || eEnd==TK_FOLLOWING
|| eEnd==TK_UNBOUNDED || eEnd==TK_PRECEDING );
assert( (eStart==TK_PRECEDING || eStart==TK_FOLLOWING)==(pStart!=0) );
assert( (eEnd==TK_FOLLOWING || eEnd==TK_PRECEDING)==(pEnd!=0) );
/* If a frame is declared "RANGE" (not "ROWS"), then it may not use
** either "<expr> PRECEDING" or "<expr> FOLLOWING".
*/
if( eType==TK_RANGE && (pStart!=0 || pEnd!=0) ){
sqlite3ErrorMsg(pParse, "RANGE must use only UNBOUNDED or CURRENT ROW");
goto windowAllocErr;
}
/* Additionally, the
** starting boundary type may not occur earlier in the following list than
** the ending boundary type:
**
** UNBOUNDED PRECEDING
** <expr> PRECEDING
** CURRENT ROW
** <expr> FOLLOWING
** UNBOUNDED FOLLOWING
**
** The parser ensures that "UNBOUNDED PRECEDING" cannot be used as an ending
** boundary, and than "UNBOUNDED FOLLOWING" cannot be used as a starting
** frame boundary.
*/
if( (eStart==TK_CURRENT && eEnd==TK_PRECEDING)
|| (eStart==TK_FOLLOWING && (eEnd==TK_PRECEDING || eEnd==TK_CURRENT))
){
sqlite3ErrorMsg(pParse, "unsupported frame delimiter for ROWS");
goto windowAllocErr;
}
pWin = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( pWin==0 ) goto windowAllocErr;
pWin->eType = eType;
pWin->eStart = eStart;
pWin->eEnd = eEnd;
pWin->pEnd = sqlite3WindowOffsetExpr(pParse, pEnd);
pWin->pStart = sqlite3WindowOffsetExpr(pParse, pStart);
return pWin;
windowAllocErr:
sqlite3ExprDelete(pParse->db, pEnd);
sqlite3ExprDelete(pParse->db, pStart);
return 0;
}
/*
@@ -859,8 +959,14 @@ Window *sqlite3WindowAlloc(
*/
void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
if( p ){
p->pWin = pWin;
if( pWin ) pWin->pOwner = p;
if( pWin ){
p->pWin = pWin;
pWin->pOwner = p;
if( p->flags & EP_Distinct ){
sqlite3ErrorMsg(pParse,
"DISTINCT is not supported for window functions");
}
}
}else{
sqlite3WindowDelete(pParse->db, pWin);
}
@@ -921,7 +1027,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
sqlite3VdbeAppendP4(v, pKeyInfo, P4_KEYINFO);
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
}
else if( p->xSFunc==nth_valueStepFunc || p->xSFunc==first_valueStepFunc ){
else if( p->zName==nth_valueName || p->zName==first_valueName ){
/* Allocate two registers at pWin->regApp. These will be used to
** store the start and end index of the current frame. */
assert( pMWin->iEphCsr );
@@ -930,7 +1036,7 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
pParse->nMem += 2;
sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
}
else if( p->xSFunc==leadStepFunc || p->xSFunc==lagStepFunc ){
else if( p->zName==leadName || p->zName==lagName ){
assert( pMWin->iEphCsr );
pWin->csrApp = pParse->nTab++;
sqlite3VdbeAddOp2(v, OP_OpenDup, pWin->csrApp, pMWin->iEphCsr);
@@ -939,24 +1045,33 @@ void sqlite3WindowCodeInit(Parse *pParse, Window *pMWin){
}
/*
** A "PRECEDING <expr>" (bEnd==0) or "FOLLOWING <expr>" (bEnd==1) has just
** been evaluated and the result left in register reg. This function generates
** VM code to check that the value is a non-negative integer and throws
** an exception if it is not.
** A "PRECEDING <expr>" (eCond==0) or "FOLLOWING <expr>" (eCond==1) or the
** value of the second argument to nth_value() (eCond==2) has just been
** evaluated and the result left in register reg. This function generates VM
** code to check that the value is a non-negative integer and throws an
** exception if it is not.
*/
static void windowCheckFrameValue(Parse *pParse, int reg, int bEnd){
static void windowCheckIntValue(Parse *pParse, int reg, int eCond){
static const char *azErr[] = {
"frame starting offset must be a non-negative integer",
"frame ending offset must be a non-negative integer"
"frame ending offset must be a non-negative integer",
"second argument to nth_value must be a positive integer"
};
static int aOp[] = { OP_Ge, OP_Ge, OP_Gt };
Vdbe *v = sqlite3GetVdbe(pParse);
int regZero = sqlite3GetTempReg(pParse);
assert( eCond==0 || eCond==1 || eCond==2 );
sqlite3VdbeAddOp2(v, OP_Integer, 0, regZero);
sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
sqlite3VdbeAddOp3(v, OP_Ge, regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
VdbeCoverage(v);
VdbeCoverageIf(v, eCond==0);
VdbeCoverageIf(v, eCond==1);
VdbeCoverageIf(v, eCond==2);
sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
VdbeCoverageNeverNullIf(v, eCond==0);
VdbeCoverageNeverNullIf(v, eCond==1);
VdbeCoverageNeverNullIf(v, eCond==2);
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
sqlite3VdbeAppendP4(v, (void*)azErr[bEnd], P4_STATIC);
sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
sqlite3ReleaseTempReg(pParse, regZero);
}
@@ -980,7 +1095,7 @@ static int windowArgCount(Window *pWin){
** the first register in an array of registers guaranteed to be large
** enough to hold the array of arguments for each function. In this case
** the arguments are extracted from the current row of csr into the
** array of registers before invoking OP_AggStep.
** array of registers before invoking OP_AggStep or OP_AggInverse
**
** Or, if csr is less than zero, then the array of registers at reg is
** already populated with all columns from the current row of the sub-query.
@@ -1025,6 +1140,8 @@ static void windowAggStep(
if( (pWin->pFunc->funcFlags & SQLITE_FUNC_MINMAX)
&& pWin->eStart!=TK_UNBOUNDED
){
int addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regArg);
VdbeCoverage(v);
if( bInverse==0 ){
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1, 1);
sqlite3VdbeAddOp2(v, OP_SCopy, regArg, pWin->regApp);
@@ -1032,25 +1149,27 @@ static void windowAggStep(
sqlite3VdbeAddOp2(v, OP_IdxInsert, pWin->csrApp, pWin->regApp+2);
}else{
sqlite3VdbeAddOp4Int(v, OP_SeekGE, pWin->csrApp, 0, regArg, 1);
VdbeCoverage(v);
VdbeCoverageNeverTaken(v);
sqlite3VdbeAddOp1(v, OP_Delete, pWin->csrApp);
sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
}
sqlite3VdbeJumpHere(v, addrIsNull);
}else if( pWin->regApp ){
assert( pWin->pFunc->xSFunc==nth_valueStepFunc
|| pWin->pFunc->xSFunc==first_valueStepFunc
assert( pWin->pFunc->zName==nth_valueName
|| pWin->pFunc->zName==first_valueName
);
assert( bInverse==0 || bInverse==1 );
sqlite3VdbeAddOp2(v, OP_AddImm, pWin->regApp+1-bInverse, 1);
}else if( pWin->pFunc->xSFunc==leadStepFunc
|| pWin->pFunc->xSFunc==lagStepFunc
}else if( pWin->pFunc->zName==leadName
|| pWin->pFunc->zName==lagName
){
/* no-op */
}else{
int addrIf = 0;
if( pWin->pFilter ){
int regTmp;
assert( nArg==pWin->pOwner->x.pList->nExpr );
assert( nArg==0 || nArg==pWin->pOwner->x.pList->nExpr );
assert( nArg || pWin->pOwner->x.pList==0 );
if( csr>0 ){
regTmp = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol+nArg,regTmp);
@@ -1065,10 +1184,12 @@ static void windowAggStep(
}
if( pWin->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
CollSeq *pColl;
assert( nArg>0 );
pColl = sqlite3ExprNNCollSeq(pParse, pWin->pOwner->x.pList->a[0].pExpr);
sqlite3VdbeAddOp4(v, OP_CollSeq, 0,0,0, (const char*)pColl, P4_COLLSEQ);
}
sqlite3VdbeAddOp3(v, OP_AggStep0, bInverse, regArg, pWin->regAccum);
sqlite3VdbeAddOp3(v, bInverse? OP_AggInverse : OP_AggStep,
bInverse, regArg, pWin->regAccum);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nArg);
if( addrIf ) sqlite3VdbeJumpHere(v, addrIf);
@@ -1100,16 +1221,15 @@ static void windowAggFinal(Parse *pParse, Window *pMWin, int bFinal){
}
}else if( pWin->regApp ){
}else{
if( bFinal==0 ){
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
}
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
if( bFinal ){
sqlite3VdbeAddOp2(v, OP_AggFinal, pWin->regAccum, windowArgCount(pWin));
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
sqlite3VdbeAddOp2(v, OP_Copy, pWin->regAccum, pWin->regResult);
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
}else{
sqlite3VdbeChangeP3(v, -1, pWin->regResult);
sqlite3VdbeAddOp3(v, OP_AggValue, pWin->regAccum, windowArgCount(pWin),
pWin->regResult);
sqlite3VdbeAppendP4(v, pWin->pFunc, P4_FUNCDEF);
}
}
}
@@ -1141,8 +1261,8 @@ static void windowPartitionCache(
*pRegSize = regRowid;
pParse->nMem += nSub + 2;
/* Martial the row returned by the sub-select into an array of
** registers. */
/* Load the column values for the row returned by the sub-select
** into an array of registers starting at reg. */
for(k=0; k<nSub; k++){
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
}
@@ -1160,9 +1280,10 @@ static void windowPartitionCache(
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
sqlite3VdbeAddOp3(v, OP_Jump, addr+2, addr+4, addr+2);
VdbeCoverage(v);
VdbeCoverageEqNe(v);
sqlite3VdbeAddOp3(v, OP_Copy, regNewPart, pMWin->regPart, nPart-1);
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
VdbeComment((v, "call flush_partition"));
}
/* Buffer the current row in the ephemeral table. */
@@ -1174,6 +1295,7 @@ static void windowPartitionCache(
/* Invoke "flush_partition" to deal with the final (or only) partition */
sqlite3VdbeAddOp2(v, OP_Gosub, regFlushPart, lblFlushPart);
VdbeComment((v, "call flush_partition"));
}
/*
@@ -1199,29 +1321,30 @@ static void windowReturnOneRow(
Window *pWin;
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc;
if( pFunc->xSFunc==nth_valueStepFunc
|| pFunc->xSFunc==first_valueStepFunc
if( pFunc->zName==nth_valueName
|| pFunc->zName==first_valueName
){
int csr = pWin->csrApp;
int lbl = sqlite3VdbeMakeLabel(v);
int tmpReg = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regResult);
if( pFunc->xSFunc==nth_valueStepFunc ){
if( pFunc->zName==nth_valueName ){
sqlite3VdbeAddOp3(v, OP_Column, pMWin->iEphCsr, pWin->iArgCol+1,tmpReg);
windowCheckIntValue(pParse, tmpReg, 2);
}else{
sqlite3VdbeAddOp2(v, OP_Integer, 1, tmpReg);
}
sqlite3VdbeAddOp3(v, OP_Add, tmpReg, pWin->regApp, tmpReg);
sqlite3VdbeAddOp3(v, OP_Gt, pWin->regApp+1, lbl, tmpReg);
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, lbl, tmpReg);
VdbeCoverage(v);
VdbeCoverageNeverNull(v);
sqlite3VdbeAddOp3(v, OP_SeekRowid, csr, 0, tmpReg);
VdbeCoverageNeverTaken(v);
sqlite3VdbeAddOp3(v, OP_Column, csr, pWin->iArgCol, pWin->regResult);
sqlite3VdbeResolveLabel(v, lbl);
sqlite3ReleaseTempReg(pParse, tmpReg);
}
else if( pFunc->xSFunc==leadStepFunc || pFunc->xSFunc==lagStepFunc ){
else if( pFunc->zName==leadName || pFunc->zName==lagName ){
int nArg = pWin->pOwner->x.pList->nExpr;
int iEph = pMWin->iEphCsr;
int csr = pWin->csrApp;
@@ -1235,10 +1358,10 @@ static void windowReturnOneRow(
}
sqlite3VdbeAddOp2(v, OP_Rowid, iEph, tmpReg);
if( nArg<2 ){
int val = (pFunc->xSFunc==leadStepFunc ? 1 : -1);
int val = (pFunc->zName==leadName ? 1 : -1);
sqlite3VdbeAddOp2(v, OP_AddImm, tmpReg, val);
}else{
int op = (pFunc->xSFunc==leadStepFunc ? OP_Add : OP_Subtract);
int op = (pFunc->zName==leadName ? OP_Add : OP_Subtract);
int tmpReg2 = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp3(v, OP_Column, iEph, pWin->iArgCol+1, tmpReg2);
sqlite3VdbeAddOp3(v, op, tmpReg2, tmpReg, tmpReg);
@@ -1265,7 +1388,7 @@ static void windowReturnOneRow(
** regCtr--;
** windowReturnOneRow()
** if( bInverse ){
** AggStep (xInverse)
** AggInverse
** }
** Next (Window.iEphCsr)
** }
@@ -1309,8 +1432,8 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
FuncDef *pFunc = pWin->pFunc;
sqlite3VdbeAddOp2(v, OP_Null, 0, pWin->regAccum);
nArg = MAX(nArg, windowArgCount(pWin));
if( pFunc->xSFunc==nth_valueStepFunc
|| pFunc->xSFunc==first_valueStepFunc
if( pFunc->zName==nth_valueName
|| pFunc->zName==first_valueName
){
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp);
sqlite3VdbeAddOp2(v, OP_Integer, 0, pWin->regApp+1);
@@ -1359,7 +1482,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
** Gosub addrGosub
** Next(csr) // if EOF goto flush_partition_done
** if( (regStart--)<=0 ){
** AggStep (csrStart, xInverse)
** AggInverse (csrStart)
** Next(csrStart)
** }
** }
@@ -1387,7 +1510,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
** Gosub addrGosub
** Next(csr) // if EOF goto flush_partition_done
** if( (regStart--)<=0 ){
** AggStep (csrStart, xInverse)
** AggInverse (csrStart)
** Next(csrStart)
** }
** }
@@ -1410,7 +1533,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
** if( new peer ) break;
** }
** while( (regPeer--)>0 ){
** AggStep (csrStart, xInverse)
** AggInverse (csrStart)
** Next(csrStart)
** }
** }
@@ -1427,7 +1550,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
** Gosub addrGosub
** Next(csr) // if EOF goto flush_partition_done
** }
** AggStep (csrStart, xInverse)
** AggInverse (csrStart)
** Next (csrStart)
** }
**
@@ -1443,7 +1566,7 @@ static int windowInitAccum(Parse *pParse, Window *pMWin){
** Gosub addrGosub
** Next(csr) // if EOF goto flush_partition_done
** if( (regStart--)<=0 ){
** AggStep (csr2, xInverse)
** AggInverse (csr2)
** Next (csr2)
** }
**
@@ -1469,8 +1592,8 @@ static void windowCodeRowExprStep(
int regEnd; /* Value of <expr> FOLLOWING */
int addrGoto;
int addrTop;
int addrIfPos1;
int addrIfPos2;
int addrIfPos1 = 0;
int addrIfPos2 = 0;
int regSize = 0;
assert( pMWin->eStart==TK_PRECEDING
@@ -1500,6 +1623,7 @@ static void windowCodeRowExprStep(
sqlite3VdbeResolveLabel(v, lblFlushPart);
sqlite3VdbeAddOp2(v, OP_Once, 0, sqlite3VdbeCurrentAddr(v)+3);
VdbeCoverage(v);
VdbeComment((v, "Flush_partition subroutine"));
sqlite3VdbeAddOp2(v, OP_OpenDup, csrStart, pMWin->iEphCsr);
sqlite3VdbeAddOp2(v, OP_OpenDup, csrEnd, pMWin->iEphCsr);
@@ -1507,11 +1631,11 @@ static void windowCodeRowExprStep(
** an exception. */
if( pMWin->pStart ){
sqlite3ExprCode(pParse, pMWin->pStart, regStart);
windowCheckFrameValue(pParse, regStart, 0);
windowCheckIntValue(pParse, regStart, 0);
}
if( pMWin->pEnd ){
sqlite3ExprCode(pParse, pMWin->pEnd, regEnd);
windowCheckFrameValue(pParse, regEnd, 1);
windowCheckIntValue(pParse, regEnd, 1);
}
/* If this is "ROWS <expr1> FOLLOWING AND ROWS <expr2> FOLLOWING", do:
@@ -1522,18 +1646,20 @@ static void windowCodeRowExprStep(
** }
** regEnd = regEnd - regStart;
*/
if( pMWin->pEnd && pMWin->pStart && pMWin->eStart==TK_FOLLOWING ){
if( pMWin->pEnd && pMWin->eStart==TK_FOLLOWING ){
assert( pMWin->pStart!=0 );
assert( pMWin->eEnd==TK_FOLLOWING );
sqlite3VdbeAddOp3(v, OP_Ge, regStart, sqlite3VdbeCurrentAddr(v)+2, regEnd);
VdbeCoverage(v);
VdbeCoverageNeverNull(v);
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
sqlite3VdbeAddOp3(v, OP_Subtract, regStart, regEnd, regEnd);
}
if( pMWin->pEnd && pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
if( pMWin->pStart && pMWin->eEnd==TK_PRECEDING ){
assert( pMWin->pEnd!=0 );
assert( pMWin->eStart==TK_PRECEDING );
sqlite3VdbeAddOp3(v, OP_Le, regStart, sqlite3VdbeCurrentAddr(v)+3, regEnd);
VdbeCoverage(v);
VdbeCoverageNeverNull(v);
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regStart);
sqlite3VdbeAddOp2(v, OP_Copy, regSize, regEnd);
}
@@ -1594,17 +1720,21 @@ static void windowCodeRowExprStep(
|| pMWin->eStart==TK_PRECEDING
|| pMWin->eStart==TK_FOLLOWING
){
int addrJumpHere = 0;
int lblSkipInverse = sqlite3VdbeMakeLabel(v);;
if( pMWin->eStart==TK_PRECEDING ){
addrJumpHere = sqlite3VdbeAddOp3(v, OP_IfPos, regStart, 0 , 1);
sqlite3VdbeAddOp3(v, OP_IfPos, regStart, lblSkipInverse, 1);
VdbeCoverage(v);
}
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
VdbeCoverage(v);
windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
if( addrJumpHere ){
sqlite3VdbeJumpHere(v, addrJumpHere);
if( pMWin->eStart==TK_FOLLOWING ){
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblSkipInverse);
}else{
sqlite3VdbeAddOp2(v, OP_Next, csrStart, sqlite3VdbeCurrentAddr(v)+1);
VdbeCoverageAlwaysTaken(v);
}
windowAggStep(pParse, pMWin, csrStart, 1, regArg, regSize);
sqlite3VdbeResolveLabel(v, lblSkipInverse);
}
if( pMWin->eEnd==TK_FOLLOWING ){
sqlite3VdbeJumpHere(v, addrIfPos1);
@@ -1615,6 +1745,7 @@ static void windowCodeRowExprStep(
sqlite3VdbeResolveLabel(v, lblFlushDone);
sqlite3VdbeAddOp1(v, OP_ResetSorter, pMWin->iEphCsr);
sqlite3VdbeAddOp1(v, OP_Return, regFlushPart);
VdbeComment((v, "end flush_partition subroutine"));
/* Jump to here to skip over flush_partition */
sqlite3VdbeJumpHere(v, addrGoto);
@@ -1670,7 +1801,7 @@ static void windowCodeRowExprStep(
**
** for(i=0; i<ctr; i++){
** Gosub addrGosub
** AggStep (xInverse, iEphCsr)
** AggInverse (iEphCsr)
** Next iEphCsr
** }
**
@@ -1703,7 +1834,7 @@ static void windowCodeRowExprStep(
** AggFinal (xValue)
** for(i=0; i<ctr; i++){
** Gosub addrGosub
** AggStep (xInverse, iEphCsr)
** AggInverse (iEphCsr)
** Next iEphCsr
** }
** Integer ctr 0
@@ -1784,9 +1915,9 @@ static void windowCodeCacheStep(
VdbeCoverageNeverTaken(v);
if( bReverse ){
int addr = sqlite3VdbeCurrentAddr(v);
int addr2 = sqlite3VdbeCurrentAddr(v);
windowAggStep(pParse, pMWin, csrLead, 0, regArg, regSize);
sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr);
sqlite3VdbeAddOp2(v, OP_Next, csrLead, addr2);
VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Rewind, csrLead, lblEmpty);
VdbeCoverageNeverTaken(v);
@@ -1903,8 +2034,8 @@ static void windowCodeDefaultStep(
pParse->nMem += nSub + 2;
/* Martial the row returned by the sub-select into an array of
** registers. */
/* Load the individual column values of the row returned by
** the sub-select into an array of registers. */
for(k=0; k<nSub; k++){
sqlite3VdbeAddOp3(v, OP_Column, iSubCsr, k, reg+k);
}
@@ -1922,7 +2053,7 @@ static void windowCodeDefaultStep(
addr = sqlite3VdbeAddOp3(v, OP_Compare, regNewPart, pMWin->regPart,nPart);
sqlite3VdbeAppendP4(v, (void*)pKeyInfo, P4_KEYINFO);
addrJump = sqlite3VdbeAddOp3(v, OP_Jump, addr+2, 0, addr+2);
VdbeCoverage(v);
VdbeCoverageEqNe(v);
windowAggFinal(pParse, pMWin, 1);
if( pOrderBy ){
addrGoto = sqlite3VdbeAddOp0(v, OP_Goto);
@@ -2081,6 +2212,7 @@ void sqlite3WindowCodeStep(
if( pMWin->eType==TK_ROWS
&& (pMWin->eStart!=TK_UNBOUNDED||pMWin->eEnd!=TK_CURRENT||!pMWin->pOrderBy)
){
VdbeModuleComment((pParse->pVdbe, "Begin RowExprStep()"));
windowCodeRowExprStep(pParse, p, pWInfo, regGosub, addrGosub);
}else{
Window *pWin;
@@ -2092,10 +2224,10 @@ void sqlite3WindowCodeStep(
for(pWin=pMWin; pWin; pWin=pWin->pNextWin){
FuncDef *pFunc = pWin->pFunc;
if( (pFunc->funcFlags & SQLITE_FUNC_WINDOW_SIZE)
|| (pFunc->xSFunc==nth_valueStepFunc)
|| (pFunc->xSFunc==first_valueStepFunc)
|| (pFunc->xSFunc==leadStepFunc)
|| (pFunc->xSFunc==lagStepFunc)
|| (pFunc->zName==nth_valueName)
|| (pFunc->zName==first_valueName)
|| (pFunc->zName==leadName)
|| (pFunc->zName==lagName)
){
bCache = 1;
break;
@@ -2105,8 +2237,10 @@ void sqlite3WindowCodeStep(
/* Otherwise, call windowCodeDefaultStep(). */
if( bCache ){
VdbeModuleComment((pParse->pVdbe, "Begin CacheStep()"));
windowCodeCacheStep(pParse, p, pWInfo, regGosub, addrGosub);
}else{
VdbeModuleComment((pParse->pVdbe, "Begin DefaultStep()"));
windowCodeDefaultStep(pParse, p, pWInfo, regGosub, addrGosub);
}
}
+95
View File
@@ -0,0 +1,95 @@
# 2018-07-15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is testing that if an IO error is encountered
# as part of an atomic F2FS commit, an attempt is made to commit the
# transaction using a legacy journal commit.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix atomic2
db close
if {[atomic_batch_write test.db]==0} {
puts "No f2fs atomic-batch-write support. Skipping tests..."
finish_test
return
}
reset_db
do_execsql_test 1.0 {
CREATE TABLE t1(x, y);
CREATE INDEX i1x ON t1(x);
CREATE INDEX i2x ON t1(y);
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
}
set setup [list \
-injectstart at_injectstart \
-injectstop at_injectstop \
]
set ::at_fail 0
set ::at_nfail 0
proc at_injectstart {iFail} {
set ::at_fail $iFail
set ::at_nfail 0
}
proc at_injectstop {} {
set ::at_fail 0
return $::at_nfail
}
proc at_vfs_callback {method file z args} {
if {$::at_fail>0} {
incr ::at_fail -1
if {$::at_fail==0} {
incr ::at_nfail
return SQLITE_IOERR
} elseif {$method=="xFileControl" && $z=="COMMIT_ATOMIC_WRITE"} {
set ::at_fail 0
}
}
return SQLITE_OK
}
testvfs tvfs -default 1
tvfs script at_vfs_callback
tvfs filter {xFileControl xWrite}
faultsim_save_and_close
do_one_faultsim_test 2.0 {*}$setup -prep {
faultsim_restore_and_reopen
} -body {
execsql {
WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100 )
INSERT INTO t1 SELECT randomblob(400), randomblob(400) FROM s;
}
} -test {
faultsim_test_result {0 {}}
set res [execsql {SELECT count(*) FROM t1; PRAGMA integrity_check}]
if {$res!="200 ok"} {
error "expected {200 ok}, got $res"
}
}
db close
tvfs delete
finish_test
+87
View File
@@ -0,0 +1,87 @@
# 2018-07-18
#
# 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 case for SQLITE_FCNTL_DATA_VERSION
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Construct a database and get its initial data version
sqlite3 db test.db
do_test dataversion1-100 {
db eval {
CREATE TABLE t1(x);
INSERT INTO t1(x) VALUES(99);
SELECT * FROM t1;
}
} {99}
set dv1 [file_control_data_version db main]
# The data version does not change by ATTACH or by changes to
# other schemas within the same connection.
#
do_test dataversion1-101 {
db eval {
ATTACH ':memory:' AS aux1;
CREATE TABLE aux1.t2(y);
CREATE TEMP TABLE t3(z);
}
file_control_data_version db main
} $dv1
# The data version does change when SQL modifies the table
do_test dataversion1-110 {
db eval {
UPDATE t1 SET x=x+1;
}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {0}
# But the data version is constant if there are changes to other
# schemas
set dv1 [file_control_data_version db main]
do_test dataversion1-120 {
db eval {
UPDATE t2 SET y=y+1;
}
file_control_data_version db
} $dv1
# Changes to the database via another connection are not detected
# until there is a read transaction.
#
sqlite3 db2 test.db
do_test dataversion1-130 {
db2 eval {
SELECT * FROM t1
}
} {100}
do_test dataversion1-131 {
file_control_data_version db
} $dv1
do_test dataversion1-132 {
db2 eval {
UPDATE t1 SET x=x+1;
}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {1}
do_test dataversion1-133 {
db eval {SELECT * FROM t1}
set dv2 [file_control_data_version db]
expr {$::dv1==$dv2}
} {0}
finish_test
+20
View File
@@ -75,4 +75,24 @@ do_execsql_test json103-300 {
FROM t1;
} {{[1,"abc"]} {[{"x":1},{"x":"abc"}]}}
# json_group_array() and json_group_object() work as window functions.
#
ifcapable windowfunc {
do_execsql_test json103-400 {
CREATE TABLE t4(x);
INSERT INTO t4 VALUES
(1),
('a,b'),
(3),
('x"y'),
(5),
(6),
(7);
SELECT json_group_array(x) OVER (ROWS 2 PRECEDING) FROM t4;
} {{[1]} {[1,"a,b"]} {[1,"a,b",3]} {["a,b",3,"x\"y"]} {[3,"x\"y",5]} {["x\"y",5,6]} {[5,6,7]}}
do_execsql_test json103-410 {
SELECT json_group_object(rowid, x) OVER (ROWS 2 PRECEDING) FROM t4;
} {{{"1":1}} {{"1":1,"2":"a,b"}} {{"1":1,"2":"a,b","3":3}} {{"2":"a,b","3":3,"4":"x\"y"}} {{"3":3,"4":"x\"y","5":5}} {{"4":"x\"y","5":5,"6":6}} {{"5":5,"6":6,"7":7}}}
}
finish_test
+18 -9
View File
@@ -71,7 +71,8 @@ proc execsql_test {tn sql} {
# with two decimal points.
#
proc execsql_float_test {tn sql} {
set F "%.2f"
set F "%.4f"
set T 0.0001
set res [execsql $sql]
set res2 [list]
foreach r $res {
@@ -79,14 +80,22 @@ proc execsql_float_test {tn sql} {
lappend res2 $r
}
puts $::fd "do_test $tn {"
puts $::fd " set myres {}"
puts $::fd " foreach r \[db eval {[string trim $sql]}\] {"
puts $::fd " lappend myres \[format $F \[set r\]\]"
puts $::fd " }"
puts $::fd " set myres"
puts $::fd "} {$res2}"
puts $::fd ""
set sql [string trim $sql]
puts $::fd [subst -nocommands {
do_test $tn {
set myres {}
foreach r [db eval {$sql}] {
lappend myres [format $F [set r]]
}
set res2 {$res2}
foreach r [set myres] r2 [set res2] {
if {[set r]<([set r2]-$T) || [set r]>([set r2]+$T)} {
error "list element [set i] does not match: got=[set r] expected=[set r2]"
}
}
set {} {}
} {}
}]
}
proc start_test {name date} {
+87
View File
@@ -154,5 +154,92 @@ do_test 400 {
} {0 {1 8192 wal ok}}
db2 close
# Reset the database yet again. This time immediately after it is closed
# and reopened. So that the VACUUM is the first statement run.
#
db close
sqlite3 db test.db
do_test 500 {
sqlite3_finalize [
sqlite3_prepare db "SELECT 1 FROM sqlite_master LIMIT 1" -1 tail
]
sqlite3_db_config db RESET_DB 1
db eval VACUUM
sqlite3_db_config db RESET_DB 0
sqlite3 db2 test.db
catchsql {
PRAGMA page_count;
PRAGMA page_size;
PRAGMA journal_mode;
PRAGMA quick_check;
} db2
} {0 {1 8192 wal ok}}
db2 close
#-------------------------------------------------------------------------
reset_db
sqlite3 db2 test.db
do_execsql_test 600 {
PRAGMA journal_mode = wal;
CREATE TABLE t1(a);
INSERT INTO t1 VALUES(1), (2), (3), (4);
} {wal}
do_execsql_test -db db2 610 {
SELECT * FROM t1
} {1 2 3 4}
do_test 620 {
set res [list]
db2 eval {SELECT a FROM t1} {
lappend res $a
if {$a==3} {
sqlite3_db_config db RESET_DB 1
db eval VACUUM
sqlite3_db_config db RESET_DB 0
}
}
set res
} {1 2 3 4}
do_execsql_test -db db2 630 {
SELECT * FROM sqlite_master
} {}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 700 {
PRAGMA page_size=512;
CREATE TABLE t1(a,b,c);
CREATE INDEX t1a ON t1(a);
CREATE INDEX t1bc ON t1(b,c);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<10)
INSERT INTO t1(a,b,c) SELECT x, randomblob(100),randomblob(100) FROM c;
PRAGMA page_count;
PRAGMA integrity_check;
} {19 ok}
do_execsql_test 710 {
UPDATE sqlite_dbpage SET data=
X'53514C69746520666F726D61742033000200030100402020000000000000001300000000000000000000000300000004000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000D00000003017C0001D801AC017C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002E03061715110145696E6465787431626374310443524541544520494E4445582074316263204F4E20743128622C63292A0206171311013F696E64657874316174310343524541544520494E44455820743161204F4E20743128612926010617111101397461626C657431743102435245415445205441424C4520743128612C622C6329' WHERE pgno=1;
}
do_execsql_test 720 {
PRAGMA integrity_check;
} {ok}
do_test 730 {
sqlite3_db_config db RESET_DB 1
db eval VACUUM
sqlite3_db_config db RESET_DB 0
} {0}
do_execsql_test 740 {
PRAGMA page_count;
PRAGMA integrity_check;
} {1 ok}
finish_test
+31
View File
@@ -0,0 +1,31 @@
# 2018-08-19
#
# 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 OOM injection in schema-related operations.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix schemafault
do_execsql_test 1.0 {
CREATE TABLE t2(aaa INTTT);
CREATE VIEW v2(xxx , yyy) AS SELECT aaa, aaa+1 FROM t2;
}
do_faultsim_test 1 -faults oom-* -prep {
} -body {
execsql { SELECT * FROM v2 }
} -test {
faultsim_test_result {0 {}}
}
finish_test
+1 -1
View File
@@ -169,6 +169,6 @@ do_execsql_test selectD-4.1 {
WHERE x1.d>5
GROUP BY x1.d) AS x2
ON t41.b=x2.d;
} {/*SEARCH SUBQUERY 0x* AS x2 USING AUTOMATIC*/}
} {/*SEARCH SUBQUERY * AS x2 USING AUTOMATIC*/}
finish_test
+8
View File
@@ -337,4 +337,12 @@ do_execsql_test skipscan1-9.2 {
SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5);
} {/USING INDEX t9a_ab .ANY.a. AND b=./}
optimization_control db skip-scan 0
do_execsql_test skipscan1-9.3 {
EXPLAIN QUERY PLAN
SELECT * FROM t9a WHERE b IN (SELECT x FROM t9b WHERE y!=5);
} {/{SCAN TABLE t9a}/}
optimization_control db skip-scan 1
finish_test
+3 -1
View File
@@ -974,7 +974,9 @@ proc query_plan_graph {sql} {
}
set a "\n QUERY PLAN\n"
append a [append_graph " " dx cx 0]
return [regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx}]
regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx} a
regsub -all {(MATERIALIZE|CO-ROUTINE|SUBQUERY) \d+\y} $a {\1 xxxxxx} a
return $a
}
# Helper routine for [query_plan_graph SQL]:
+16
View File
@@ -112,4 +112,20 @@ do_execsql_test upsert1-500 {
SELECT * FROM t1;
} {1 2}
# 2018-07-11
# Ticket https://sqlite.org/src/tktview/79cad5e4b2e219dd197242e9e5f4
# UPSERT leads to a corrupt index.
#
do_execsql_test upsert1-600 {
DROP TABLE t1;
CREATE TABLE t1(b UNIQUE, a INT PRIMARY KEY) WITHOUT ROWID;
INSERT OR IGNORE INTO t1(a) VALUES('1') ON CONFLICT(a) DO NOTHING;
PRAGMA integrity_check;
} {ok}
do_execsql_test upsert1-610 {
DELETE FROM t1;
INSERT OR IGNORE INTO t1(a) VALUES('1'),(1) ON CONFLICT(a) DO NOTHING;
PRAGMA integrity_check;
} {ok}
finish_test
+97
View File
@@ -0,0 +1,97 @@
# 2018 July 4
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
ifcapable !wal {finish_test ; return }
set testprefix walprotocol2
#-------------------------------------------------------------------------
# When recovering the contents of a WAL file, a process obtains the WRITER
# lock, then locks all other bytes before commencing recovery. If it fails
# to lock all other bytes (because some other process is holding a read
# lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the
# caller. Test this (test case 1.3).
#
# Also test the effect of hitting an SQLITE_BUSY while attempting to obtain
# the WRITER lock (should be the same). Test case 1.4.
#
do_execsql_test 1.0 {
PRAGMA journal_mode = wal;
CREATE TABLE x(y);
INSERT INTO x VALUES('z');
} {wal}
db close
proc lock_callback {method filename handle lock} {
# puts "$method $filename $handle $lock"
}
testvfs T
T filter xShmLock
T script lock_callback
sqlite3 db test.db -vfs T
sqlite3 db2 test.db -vfs T
do_execsql_test 2.0 {
SELECT * FROM x;
} {z}
do_execsql_test -db db2 2.1 {
SELECT * FROM x;
} {z}
#---------------------------------------------------------------
# Attempt a "BEGIN EXCLUSIVE" using connection handle [db]. This
# causes SQLite to open a read transaction, then a write transaction.
# Rig the xShmLock() callback so that just before the EXCLUSIVE lock
# for the write transaction is taken, connection [db2] jumps in and
# modifies the database. This causes the "BEGIN EXCLUSIVE" to throw
# an SQLITE_BUSY_SNAPSHOT error.
#
proc lock_callback {method filename handle lock} {
if {$lock=="0 1 lock exclusive"} {
proc lock_callback {method filename handle lock} {}
db2 eval { INSERT INTO x VALUES('y') }
}
}
do_catchsql_test 2.2 {
BEGIN EXCLUSIVE;
} {1 {database is locked}}
do_test 2.3 {
sqlite3_extended_errcode db
} {SQLITE_BUSY}
#---------------------------------------------------------------
# Same again, but with a busy-handler. This time, following the
# SQLITE_BUSY_SNAPSHOT error the busy-handler is invoked and then the
# whole thing retried from the beginning. This time it succeeds.
#
proc lock_callback {method filename handle lock} {
if {$lock=="0 1 lock exclusive"} {
proc lock_callback {method filename handle lock} {}
db2 eval { INSERT INTO x VALUES('x') }
}
}
db timeout 10
do_catchsql_test 2.4 {
BEGIN EXCLUSIVE;
} {0 {}}
do_execsql_test 2.5 {
SELECT * FROM x;
COMMIT;
} {z y x}
finish_test
+13 -8
View File
@@ -308,24 +308,29 @@ foreach {tn window} {
"
execsql_test 1.$tn.15.1 "
SELECT string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE a%2=0) OVER (ORDER BY a $window) FROM t2
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE a%2=0) OVER win FROM t2
WINDOW win AS (ORDER BY a $window)
"
execsql_test 1.$tn.15.2 "
SELECT string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE 0=1) OVER (ORDER BY a $window) FROM t2
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE 0=1) OVER win FROM t2
WINDOW win AS (ORDER BY a $window)
"
execsql_test 1.$tn.15.3 "
SELECT string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE 1=0) OVER (PARTITION BY (a%10) ORDER BY a $window) FROM t2
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE 1=0) OVER win FROM t2
WINDOW win AS (PARTITION BY (a%10) ORDER BY a $window)
"
execsql_test 1.$tn.15.4 "
SELECT string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE a%2=0) OVER (PARTITION BY (a%10) ORDER BY a $window) FROM t2
SELECT count(*) OVER win, string_agg(CAST(b AS TEXT), '.')
FILTER (WHERE a%2=0) OVER win FROM t2
WINDOW win AS (PARTITION BY (a%10) ORDER BY a $window)
"
}
finish_test
+4422 -2093
View File
File diff suppressed because one or more lines are too long
+28
View File
@@ -332,5 +332,33 @@ execsql_test 9.5 {
SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
}
execsql_float_test 9.6 {
SELECT percent_rank() OVER () FROM t1
}
execsql_float_test 9.7 {
SELECT cume_dist() OVER () FROM t1
}
execsql_test 10.0 {
DROP TABLE IF EXISTS t7;
CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER);
INSERT INTO t7(id, a, b) VALUES
(1, 1, 2), (2, 1, NULL), (3, 1, 4),
(4, 3, NULL), (5, 3, 8), (6, 3, 1);
}
execsql_test 10.1 {
SELECT id, min(b) OVER (PARTITION BY a ORDER BY id) FROM t7;
}
execsql_test 10.2 {
SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
}
execsql_test 10.3 {
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
}
finish_test
+36
View File
@@ -1233,4 +1233,40 @@ do_execsql_test 9.5 {
SELECT DISTINCT x, rank() OVER (ORDER BY x) FROM t2 ORDER BY 1,2
} {1 1 4 4 6 6 7 7}
do_test 9.6 {
set myres {}
foreach r [db eval {SELECT percent_rank() OVER () FROM t1}] {
lappend myres [format %.2f [set r]]
}
set myres
} {0.00 0.00 0.00}
do_test 9.7 {
set myres {}
foreach r [db eval {SELECT cume_dist() OVER () FROM t1}] {
lappend myres [format %.2f [set r]]
}
set myres
} {1.00 1.00 1.00}
do_execsql_test 10.0 {
DROP TABLE IF EXISTS t7;
CREATE TABLE t7(id INTEGER PRIMARY KEY, a INTEGER, b INTEGER);
INSERT INTO t7(id, a, b) VALUES
(1, 1, 2), (2, 1, NULL), (3, 1, 4),
(4, 3, NULL), (5, 3, 8), (6, 3, 1);
} {}
do_execsql_test 10.1 {
SELECT id, min(b) OVER (PARTITION BY a ORDER BY id) FROM t7;
} {1 2 2 2 3 2 4 {} 5 8 6 1}
do_execsql_test 10.2 {
SELECT id, lead(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
} {1 {} 2 2 3 {} 4 {} 5 {} 6 8}
do_execsql_test 10.3 {
SELECT id, lag(b, -1) OVER (PARTITION BY a ORDER BY id) FROM t7;
} {1 {} 2 4 3 {} 4 8 5 1 6 {}}
finish_test
+10
View File
@@ -82,6 +82,16 @@ do_execsql_test 2.1 {
SELECT sumint(a) OVER (ORDER BY rowid ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) FROM t1 ORDER BY rowid;
} {10 11 12 8 10 5}
test_override_sum db
do_catchsql_test 3.0 {
SELECT sum(a) OVER
(ORDER BY b ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
FROM t1;
} {1 {sum() may not be used as a window function}}
do_execsql_test 3.1 {
SELECT sum(a) FROM t1;
} {21}
finish_test
+196
View File
@@ -139,5 +139,201 @@ do_execsql_test 5.4 {
SELECT sum(window) OVER window window FROM window window window window AS (ORDER BY window);
} {2 6 12}
do_execsql_test 5.5 {
SELECT count(*) OVER win FROM over
WINDOW win AS (ORDER BY x ROWS BETWEEN +2 FOLLOWING AND +3 FOLLOWING)
} {1 0 0}
#-------------------------------------------------------------------------
#
do_execsql_test 6.0 {
SELECT LIKE('!', '', '!') x WHERE x;
} {}
do_execsql_test 6.1 {
SELECT LIKE("!","","!")""WHeRE"";
} {}
do_catchsql_test 6.2 {
SELECT LIKE("!","","!")""window"";
} {1 {near "window": syntax error}}
reset_db
do_execsql_test 7.0 {
CREATE TABLE t1(x TEXT);
CREATE INDEX i1 ON t1(x COLLATE nocase);
INSERT INTO t1 VALUES('');
}
do_execsql_test 7.1 {
SELECT count(*) FROM t1 WHERE x LIKE '!' ESCAPE '!';
} {0}
#-------------------------------------------------------------------------
#
do_execsql_test 8.0 {
CREATE TABLE IF NOT EXISTS "sample" (
"id" INTEGER NOT NULL PRIMARY KEY,
"counter" INTEGER NOT NULL,
"value" REAL NOT NULL
);
INSERT INTO "sample" (counter, value)
VALUES (1, 10.), (1, 20.), (2, 1.), (2, 3.), (3, 100.);
}
do_execsql_test 8.1 {
SELECT "counter", "value", RANK() OVER w AS "rank"
FROM "sample"
WINDOW w AS (PARTITION BY "counter" ORDER BY "value" DESC)
ORDER BY "counter", RANK() OVER w
} {
1 20.0 1 1 10.0 2 2 3.0 1 2 1.0 2 3 100.0 1
}
do_execsql_test 8.2 {
SELECT "counter", "value", SUM("value") OVER
(ORDER BY "id" ROWS 2 PRECEDING)
FROM "sample"
ORDER BY "id"
} {
1 10.0 10.0 1 20.0 30.0 2 1.0 31.0 2 3.0 24.0 3 100.0 104.0
}
do_execsql_test 8.3 {
SELECT SUM("value") OVER
(ORDER BY "id" ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
FROM "sample"
ORDER BY "id"
} {
10.0 30.0 31.0 24.0 104.0
}
do_execsql_test 9.0 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT x, group_concat(x) OVER (ORDER BY x ROWS 2 PRECEDING)
FROM c;
} {
1 1 2 1,2 3 1,2,3 4 2,3,4 5 3,4,5
}
do_catchsql_test 9.1 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT x, group_concat(x) OVER (ORDER BY x RANGE 2 PRECEDING)
FROM c;
} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}}
do_catchsql_test 9.2 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT x, group_concat(x) OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND 2 FOLLOWING)
FROM c;
} {1 {RANGE must use only UNBOUNDED or CURRENT ROW}}
do_catchsql_test 9.3 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count(DISTINCT x) OVER (ORDER BY x) FROM c;
} {1 {DISTINCT is not supported for window functions}}
do_catchsql_test 9.4 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (ORDER BY x RANGE UNBOUNDED FOLLOWING) FROM c;
} {1 {near "FOLLOWING": syntax error}}
do_catchsql_test 9.5 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (ORDER BY x RANGE BETWEEN UNBOUNDED FOLLOWING AND UNBOUNDED FOLLOWING) FROM c;
} {1 {near "FOLLOWING": syntax error}}
do_catchsql_test 9.6 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (ORDER BY x RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED PRECEDING) FROM c;
} {1 {near "PRECEDING": syntax error}}
foreach {tn frame} {
1 "BETWEEN CURRENT ROW AND 4 PRECEDING"
2 "4 FOLLOWING"
3 "BETWEEN 4 FOLLOWING AND CURRENT ROW"
4 "BETWEEN 4 FOLLOWING AND 2 PRECEDING"
} {
do_catchsql_test 9.7.$tn "
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (
ORDER BY x ROWS $frame
) FROM c;
" {1 {unsupported frame delimiter for ROWS}}
}
do_catchsql_test 9.8.1 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (
ORDER BY x ROWS BETWEEN a PRECEDING AND 2 FOLLOWING
) FROM c;
} {1 {frame starting offset must be a non-negative integer}}
do_catchsql_test 9.8.2 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5)
SELECT count() OVER (
ORDER BY x ROWS BETWEEN 2 PRECEDING AND a FOLLOWING
) FROM c;
} {1 {frame ending offset must be a non-negative integer}}
do_execsql_test 10.0 {
WITH t1(a,b) AS (VALUES(1,2))
SELECT count() FILTER (where b<>5) OVER w1
FROM t1
WINDOW w1 AS (ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING);
} {1}
foreach {tn stmt} {
1 "SELECT nth_value(b, 0) OVER (ORDER BY a) FROM t1"
2 "SELECT nth_value(b, -1) OVER (ORDER BY a) FROM t1"
3 "SELECT nth_value(b, '4ab') OVER (ORDER BY a) FROM t1"
4 "SELECT nth_value(b, NULL) OVER (ORDER BY a) FROM t1"
5 "SELECT nth_value(b, 8.5) OVER (ORDER BY a) FROM t1"
} {
do_catchsql_test 10.1.$tn "
WITH t1(a,b) AS ( VALUES(1, 2), (2, 3), (3, 4) )
$stmt
" {1 {second argument to nth_value must be a positive integer}}
}
foreach {tn stmt res} {
1 "SELECT nth_value(b, 1) OVER (ORDER BY a) FROM t1" {2 2 2}
2 "SELECT nth_value(b, 2) OVER (ORDER BY a) FROM t1" {{} 3 3}
3 "SELECT nth_value(b, '2') OVER (ORDER BY a) FROM t1" {{} 3 3}
4 "SELECT nth_value(b, 2.0) OVER (ORDER BY a) FROM t1" {{} 3 3}
5 "SELECT nth_value(b, '2.0') OVER (ORDER BY a) FROM t1" {{} 3 3}
6 "SELECT nth_value(b, 10000000) OVER (ORDER BY a) FROM t1" {{} {} {}}
} {
do_execsql_test 10.2.$tn "
WITH t1(a,b) AS ( VALUES(1, 2), (2, 3), (3, 4) )
$stmt
" $res
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test 11.0 {
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES(10),(15),(20),(20),(25),(30),(30),(50);
CREATE TABLE t3(x INT, y VARCHAR);
INSERT INTO t3(x,y) VALUES(10,'ten'),('15','fifteen'),(30,'thirty');
}
do_execsql_test 11.1 {
SELECT a, (SELECT y FROM t3 WHERE x=a) FROM t1 ORDER BY a;
} {
10 ten 15 fifteen 20 {} 20 {} 25 {} 30 thirty 30 thirty 50 {}
}
do_execsql_test 11.2 {
SELECT a, (SELECT y FROM t3 WHERE x=a), sum(a) OVER (ORDER BY a)
FROM t1 ORDER BY a;
} {
10 ten 10 15 fifteen 25 20 {} 65 20 {} 65
25 {} 90 30 thirty 150 30 thirty 150 50 {} 200
}
finish_test
+33
View File
@@ -129,5 +129,38 @@ do_faultsim_test 5 -start 1 -faults oom-* -prep {
faultsim_test_result {0 {5 1 9 5 9 9}}
}
do_faultsim_test 6 -faults oom-* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT percent_rank() OVER (), cume_dist() OVER () FROM t1
}
} -test {
faultsim_test_result {0 {0.0 1.0 0.0 1.0 0.0 1.0}}
}
do_faultsim_test 7 -faults oom-* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT percent_rank() OVER (), cume_dist() OVER () FROM t1
}
} -test {
faultsim_test_result {0 {0.0 1.0 0.0 1.0 0.0 1.0}}
}
do_faultsim_test 8 -faults oom-t* -prep {
faultsim_restore_and_reopen
} -body {
execsql {
SELECT a, sum(b) OVER win1 FROM t1
WINDOW win1 AS (PARTITION BY a ),
win2 AS (PARTITION BY b )
ORDER BY a;
}
} -test {
faultsim_test_result {0 {1 2 5 6 9 10}}
}
finish_test
+4 -1
View File
@@ -550,6 +550,7 @@ static YYACTIONTYPE yy_find_shift_action(
#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
j<YY_ACTTAB_COUNT &&
#endif
j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) &&
yy_lookahead[j]==YYWILDCARD && iLookAhead>0
){
#ifndef NDEBUG
@@ -1065,9 +1066,11 @@ void Parse(
*/
int ParseFallback(int iToken){
#ifdef YYFALLBACK
if( iToken<sizeof(yyFallback)/sizeof(yyFallback[0]) ){
if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){
return yyFallback[iToken];
}
#else
(void)iToken;
#endif
return 0;
}