Compare commits

..

348 Commits

Author SHA1 Message Date
drh 5afd67b3c3 Use extra assert() statement to silence harmless static analyzer warnings.
FossilOrigin-Name: 174c2b2eef5fecd96a5fc89b81032fe81f7801f12097cea10e7e7f0a02114813
2023-12-05 19:24:07 +00:00
drh a0de45459e Miscellaneous comment cleanup and typo fixes.
FossilOrigin-Name: 59446dc0bd0091572122a3c8b4653d7a2dc867d16c4a5919f79b81bc3a673ce3
2023-12-05 18:28:15 +00:00
drh 8eac91fab7 Use strspn() to accelerate whitespace bypass in the JSON parser.
FossilOrigin-Name: 843197df08352bdff4b87be91d160e574572aded0d0c66142fd960000c0b4701
2023-12-05 12:52:13 +00:00
drh 590aaff992 Small performance gain by unwinding the string literal delimiter search
loop in the JSON parser by one more level.

FossilOrigin-Name: 4c587feac153e8ebe526559ec3d254f545f81e8d1ed3126f91a5ff25ec4aa72e
2023-12-05 12:22:05 +00:00
drh 78f7d2f4c1 Clean up the JSONB performance test script.
FossilOrigin-Name: 905301075a7fc1010ee7e754867b1b698c9b8576d50e98125def32a5dfb7ee9d
2023-12-05 12:20:58 +00:00
drh fa43e21711 Use an assert() to fix a harmless static analyzer warning.
FossilOrigin-Name: a249ca657e624028bc6b3d2c2bcedd7162d118addb7d62ce519920cecebf1860
2023-12-05 01:44:15 +00:00
drh ae2e972802 Fix OOM and corrupt JSONB handling in json_patch().
FossilOrigin-Name: 1910feb0b7d5cc2b810c3322f6cca281d8730182d30d162bd7bb56800979ea91
2023-12-05 00:17:17 +00:00
drh 3cdb079476 Rename the internal routine jsonMergePatchBlob() to just jsonMergePatch().
FossilOrigin-Name: ebf667b616235bb64b83832008342ba5e7b10b2c170d7cebc431f040fef7ecfb
2023-12-04 23:12:57 +00:00
drh f26e26afc5 Fixes to error handling in json_array_length().
FossilOrigin-Name: aa85df2d26b74c171c55bde19ef17c4f11f40b8af7181bbf7162f87cdea7e88b
2023-12-04 19:32:17 +00:00
drh 0b8b1c309d Do not make the input JSONB editable in json_remove() if there are no PATH
argument.

FossilOrigin-Name: 66594544f3ba9977475a3e3f74404eb2b2fb845053b28bd24c2b52c7df94e9d7
2023-12-04 19:14:13 +00:00
drh 3fedb7e59e Fix errors in rendering JSON5 escape sequences embedded in JSONB.
FossilOrigin-Name: f1a51ae3863557526a51c6e98e71fcdf4f1ed14a36212b3c90f7408f926345e4
2023-12-04 18:53:10 +00:00
drh 9c794b9bff Continuing simplifications and code cleanup.
FossilOrigin-Name: ddf92b5059a9106753fd18b82ba8daa269a62af947561c460790107b83416f0b
2023-12-04 17:40:28 +00:00
drh 99c41692f1 Remove reachable ALWAYS and NEVER macros.
FossilOrigin-Name: f601de3eeabd85993c1f5ee96b62de6fdabbeae2fe8950e00d08feb48d42c498
2023-12-04 16:01:39 +00:00
drh 732fb64ad3 Two new NEVER macros.
FossilOrigin-Name: 52632c92cb06faf0e804654b3490fd6c199521107bd30c8fcbc3a2a5a488098f
2023-12-04 15:22:42 +00:00
drh dc138cb186 Repair issues and inefficiencies found during testing.
FossilOrigin-Name: ae973cb1515f9d76409c92a2ca2ffd6b71f32b0b490a4886770e7c1b90f12611
2023-12-04 13:12:45 +00:00
drh 2ff73a5f3e Better pre-scan size estimations for objects in the JSON parser resulting
in fewer reallocations and memmove operations.

FossilOrigin-Name: 526b27f90897f5e35dfff7257daf6c4ce4798d649b09b8aecfb02df0449e3c51
2023-12-04 01:14:23 +00:00
drh b7fd951be4 Back off on the use of strlen() for situations where sqlite3_value_bytes()
will work as well, for performance.

FossilOrigin-Name: 79fb54fbb8b9c30f47cdbd437d24a21542716241e822749e5e28c9fbc449bfa8
2023-12-04 00:31:58 +00:00
drh 9af45dc482 Remove dead code. Improved reporting of errors in JSON inputs.
FossilOrigin-Name: 2eaa738e6b5c1b67b3e57c868d9c3a30eea38a0b3b8b02482f06d57a45b10921
2023-12-03 23:38:24 +00:00
drh 16e8a5b2f3 Avoid problems when the path argument to json_tree() contains embedded U+0000
characters.

FossilOrigin-Name: 9f055091af01a5dddba1a7e9868ad030c8f206237e1569215cb161e53e54aa71
2023-12-03 23:30:59 +00:00
drh a3bf077b60 Ensure that OOM conditions in the generation of the "bad JSON path" error
message result in an SQLITE_NOMEM error.

FossilOrigin-Name: aa0e02b5c26a2ef3d6216a0ed8bc01382be43173485f898cb63f2a8c559f2e74
2023-12-03 20:11:35 +00:00
drh 0a18a5807a Enable incorrect JSONB to be rendered into text without hitting an
assertion for a bad whitespace escape in a string.

FossilOrigin-Name: 4d6a9a217df6792b41766b774fb0c0553b45f9104c26a0955bf4a30862d7d7bf
2023-12-03 19:59:45 +00:00
drh 78fa0186b8 Do not let bad hexadecimal digits in malformed JSONB cause an assertion fault.
FossilOrigin-Name: 8dec1ba1e5076ff596756e00c1e2ada0245f168a503dd1cadadf848331acfac3
2023-12-03 11:54:39 +00:00
drh eb18ae3089 Minor code changes for consistency and to simplify testing.
FossilOrigin-Name: df272bd837910ad9e03e222716a1201a601399664365f1dcf73d5932372518ed
2023-12-03 00:51:30 +00:00
drh c78c3c91ae Implement strict JSONB checking in the json_valid() function.
FossilOrigin-Name: 0f26d38880fcbc207abcc94dbc170a7428bab1b4f0b7731aaf5bee0224000994
2023-12-02 21:39:34 +00:00
drh 8f8d481485 Fix harmless compiler warnings reported by MSVC.
FossilOrigin-Name: 419652c0c82980bd043584dcd2976f91dfff7b926b216d597698299850b855c0
2023-12-02 20:37:45 +00:00
drh c1e85742da Code and comment cleanup. Everything should work the same.
FossilOrigin-Name: c640754df0d3ffdad994745f0d0e10c8f19f424b87f6a6e6e269491a0350b950
2023-12-02 20:25:36 +00:00
drh 53c2160db0 Fix harmless compiler warnings. Refactor some identifier names for
clearer presentation.

FossilOrigin-Name: 7e3941502789c5afaf19b08112f464abf5e3cba7f92fc9290af2a0f96127ad9a
2023-12-02 18:17:38 +00:00
drh a11aaff05a Take extra care to ensure that JSONB values that are in cache are actually
owned by the JSON subsystem, and that ownership of such values is not handed
back to the bytecode engine.

FossilOrigin-Name: 1304534001e9ef66c6b12752b69d790bfa3427cc803f87cc48ca22ae12df0fdf
2023-12-02 18:04:27 +00:00
drh 05db513435 Protect a memcpy() against OOM conditions.
FossilOrigin-Name: 26144d1c25ae0435db568009ba05e485d23d146f2b1f29f3a426c87860316aed
2023-12-02 16:11:22 +00:00
drh 2c26bde4ff Do not allow a JsonParse object to be considered "editable" after an OOM.
FossilOrigin-Name: c6bacf57bd6fe0fee00c9d41163a270b60997c20659949971bbf5c6c62622bfe
2023-12-02 15:59:48 +00:00
drh 4cd397c0d9 Fix potential unsigned integer underflow in jsonAppendString().
FossilOrigin-Name: d2fba2cbdc3870d34228c1a9446eced884325acc183900d7dd0b96132570fb4a
2023-12-02 15:06:43 +00:00
drh 82136d90f8 Minor fix to the header comment on jsonXlateTextToBlob().
FossilOrigin-Name: c3677ba410208c07b711f5f526eb5cf039a8eee49f632c7ae04fa55cdfbb9058
2023-12-02 14:55:46 +00:00
drh f0b8b16317 Performance optimization in jsonAppendString().
FossilOrigin-Name: fdf00e96239c73fb67e2acecc5b95f55a1fc51c3deed4512613c0d6070ce5805
2023-12-02 14:16:47 +00:00
drh 679c90850c Simplification and optimization of the JSON parser.
FossilOrigin-Name: f5ec9485119a2a6cb33eb864c7ca9b41d4a2ed08ab6ad9a6b0dd9358ab253576
2023-12-02 13:36:52 +00:00
drh 6df61985d4 Unroll a loop in the parser for a performance increase.
FossilOrigin-Name: a6dc29e4d5e13949e0fcd9d5dde575c2670eb10a230ab9df3806fc8c3016c540
2023-12-02 01:38:53 +00:00
drh 5ec9c916ad Fix harmless compiler warnings and enhance performance the parser.
FossilOrigin-Name: 285633da6d188547e52f07779e209c9e5f3dc33ce0668e14858f3337889ef4b8
2023-12-02 01:06:33 +00:00
drh 3af20cf3a0 Performance optimization in the JSON parser.
FossilOrigin-Name: 68d191f40e708962ec88e0c245b4496bc4a671300484b1cc0f3fc7e6d199a6e6
2023-12-01 22:01:26 +00:00
drh 03075fa868 JSON cache is now more effective.
FossilOrigin-Name: 443a3f3a8e64d81cad8300a30e2cc57c4e39f69b5669ac8b550c590ae9f1134a
2023-12-01 18:49:02 +00:00
drh 063d0d4c3a Fix up the JSON cache to work better.
FossilOrigin-Name: 1fdbc39521f63aedc6f08ecaafa54ea467b8c6316a692a18ad01eecbf22a0977
2023-12-01 18:46:14 +00:00
drh 5bfa7e65d1 Cache is working better, but does not preserve the hasJson5 flag.
FossilOrigin-Name: a12add7ab9f5aee5bb2ede0c4d22e599dd28f7a107dce72b2ea48ef92d233e8a
2023-12-01 13:28:13 +00:00
drh ca1ce7773c First attempt to get the JSON text-to-binary cache working. All test cases
pass, but the cache seems not to help much.

FossilOrigin-Name: 25ed295f300fea6185104a73721076bccd2b2a6e411c78564266fa6dca4ff70c
2023-12-01 12:57:12 +00:00
drh 4b9ed1b256 Remove all trace of JsonNode from the JSON implementation. The JSONB format
is used as the internal binary encoding for searching and editing.

FossilOrigin-Name: 11ebb5f712cc7a515e2e0f2be8c1d71de20c97fe5b74c4f4d72c84fd21182d35
2023-11-30 23:36:14 +00:00
drh 38aeb97f27 Convert json_valid() over to using only JSONB as its internal format.
FossilOrigin-Name: 7b5756fa6d00b093bf083a8d7a5ef5485f7a09e4eac473785c8380688f861a1b
2023-11-30 20:57:48 +00:00
drh 276042bd23 Convert json_type() to use JSONB internally.
FossilOrigin-Name: 83074835b900ce85cf67059e674ce959801505c37592671af25ca0af7ed483f1
2023-11-30 19:29:56 +00:00
drh 0ab1e25468 Convert json_insert(), json_replace(), and json_set() over to using only
JSONB internally.

FossilOrigin-Name: 4e2083e86f19ef7634f0b253fb924e52014b43ed0ce8acc51c36f3c5682180a6
2023-11-30 19:11:14 +00:00
drh 66795962b5 Enhance json_set() and json_insert() so that they create missing
substructure.

FossilOrigin-Name: cc7a641ab5ae739d31c24f0ad0caeb15a481a63fa8f13720718ea922c25862ff
2023-11-30 19:06:27 +00:00
drh 7394a6ef57 Simplification of the new JSON insert/set test cases.
FossilOrigin-Name: 04c0d5644372446c924a2e31a26edf51ddc563a1990d170b0ed4739e3e8b239b
2023-11-30 16:17:09 +00:00
drh ad27c437ff New test cases for insert/set/replace with paths that indicate substructure
that does not yet exist.

FossilOrigin-Name: 146c717c51940b2139befc45ac74e7a1c36ef3c32fd3cfe35b334488eebe6298
2023-11-30 12:04:14 +00:00
drh bfc7e62be4 Convert json_insert(), json_replace(), json_set() to use JSONB internally.
Mostly working, but some corner cases are still not quite right.

FossilOrigin-Name: 99c8f6bd5c9a31b6d00f92e383bec8a8235ed553916ad59adbb1b7663f6ebff1
2023-11-30 00:52:33 +00:00
drh 694beecf2b Convert the json_error_position() routine to use only JSONB internally.
FossilOrigin-Name: e7a8ba35bff6fde55827f978de5b343b6c134c7fa53827f5c63915a9dc2598ad
2023-11-29 20:06:49 +00:00
drh da2578391d The json_patch() function now operates exclusively on JSONB. This patch
also includes improvements to JSONB debug printing routines.

FossilOrigin-Name: fee19d0098242110d2c44ec7b9620c1210ef3f87913305f66ec85d277dd96ab6
2023-11-29 17:36:54 +00:00
drh 6d7afd8ba8 Merge all the latest trunk enhancements into the jsonb branch.
FossilOrigin-Name: 1a59fcab2179cc3b52ecd3de7d2018db96ac149aaff521959773a517b8d9ac3e
2023-11-29 12:18:02 +00:00
drh 2ba5534101 The assertion change at check-in [7946c79567b0ccd3] is insufficient to fix
the problem of a Table object being deleted out from under the OP_VCheck
opcode.  We need to reference count the Table, which is accomplished here.

FossilOrigin-Name: cad269d5e274443c39203a56603b991accc0399135d436996fc039d1d28ec9db
2023-11-29 02:45:09 +00:00
drh 4b54d6cdaf Convert the json_array_length() function to use JSONB instead of JsonNodes.
FossilOrigin-Name: 5ab790736d943e08f097efcee5cfbf0d83c65b0a53f273060330ba719affa5e5
2023-11-29 01:38:15 +00:00
drh 748178a9fb Fix all known problems with JSONB json_extract().
FossilOrigin-Name: d5f48c57e975ac468cf29a43a5d0b56ef6d06cf35a8b0bddf87ec1c0fc7ae028
2023-11-28 23:26:55 +00:00
drh 1f8c7c7053 Do not set the J subtype when the output is JSONB.
FossilOrigin-Name: 4f106b64fe8988435872806bd0a6c223b61f53af0dd1c47c847bb4eec4e03e27
2023-11-28 23:18:04 +00:00
drh 1ef232c0e1 Preserve flexibility in the format of the RHS of -> and ->> operators found
in legacy.

FossilOrigin-Name: 6231ec43adb7436195eb1497de39a6c13c6b4f1c5032e6ea52515d214e61fdbc
2023-11-28 20:33:20 +00:00
drh 1cab41e290 Attempt to get json_extract() working with pure JSONB only, and without
the use of JsonNode.  Mostly working, but there are some differences from
legacy in corner cases.

FossilOrigin-Name: 8c324af1eca27e86adc45622af4f3b06a67a3f968596ac58aa7434b1f6f05f3c
2023-11-28 20:25:23 +00:00
drh ef97f8360a The json_remove() function now uses only JSONB, never JsonNodes, internally.
FossilOrigin-Name: b69786e746ae2b927b64d9871fd120b7f8f06cc53739fd46a4da51aa16cf8576
2023-11-28 18:16:02 +00:00
dan 940b23bc3a In SQLITE_ENABLE_SETLK_TIMEOUT builds, use blocking locks in place of sleep() calls when opening a read-transaction.
FossilOrigin-Name: 4c055b7a6e4533e1e571773456226ca7038ce372df3eedbbbcd9a81e8652a6cf
2023-11-28 17:12:42 +00:00
dan b8950e0f45 Handle an SQLITE_BUSY_TIMEOUT error if one occurs while attempting a shared lock on a read-lock slot.
FossilOrigin-Name: 5fbf3906d272df3eb981f67455eb35f649ad2774cba9fc3f077b28d9bef3f0cb
2023-11-28 15:29:04 +00:00
drh 26cd4b57df Activate the ability of json_patch() to work on JSONB.
FossilOrigin-Name: 11aba347ff7c639500eec904e212eabe889b077351b946cfeac2b74b9703672a
2023-11-28 13:38:22 +00:00
drh ec1f59f0cd All legacy tests are passing.
FossilOrigin-Name: 2c436806b8d5f57de99c00f6154b038454fb9ae427d00d7b4a46ab9c7c69bcb9
2023-11-28 13:35:53 +00:00
drh 5026ddb83d The json_patch() code for JSONB compiles and works sometimes, but there are
still issues.  Incremental check-in.

FossilOrigin-Name: e0099464a0045a04f4ccf29bc2b8325fc8c7f39ccf4847e74818f928c9153588
2023-11-28 12:28:28 +00:00
drh f46f89df97 More aggressive use of jsonBlobEdit(). Improvements to the MergePatch
implementation sketch.

FossilOrigin-Name: fbca9570fd2e1465739e4d3a8d9bb40fad594fd78ab49b2cb34efa27ebdd8361
2023-11-28 00:27:58 +00:00
drh eb04a0bb7b Add untested (#ifdefed-out) code for the MergePatch algorithm against JSONB.
Add (and test) the jsonBlobEdit() routine that is needed by the new MergePatch.

FossilOrigin-Name: 4d353387fc10e1038cfdd86e66007bf728c231a928e588897bbee0fbfe76f225
2023-11-27 23:46:12 +00:00
dan bae2d0f2eb Have SQLITE_ENABLE_SETLK_TIMEOUT builds block when locking a read-lock slot.
FossilOrigin-Name: f797baf47cf7859cfd8ce248f4f3087af4551a7040af990333426e5a7c269504
2023-11-27 20:37:03 +00:00
dan e52854a9e6 In SQLITE_ENABLE_SETLK_TIMEOUT builds, use blocking locks in place of sleep() when opening a read-transaction.
FossilOrigin-Name: a51ef39998e25e86bd0600e71d15011b12e05f4319608018293bdaecb09e8c97
2023-11-27 19:22:50 +00:00
drh 8a3034add8 Enhance the (SQLITE_DEBUG-only) json_parse() routine so that it shows a
decoding of JSONB when given a BLOB argument.

FossilOrigin-Name: af267868562e0799ad691dccad05f17afbc34d609eede8c55f57d209290246ef
2023-11-27 17:13:18 +00:00
drh 821a4c9f8c Give the json_valid() function an optional second argument that determines
what is meant by "valid".

FossilOrigin-Name: a4e19ad43dac81e7655ec03ff69bb99d1d02b0c227034c90fb41415fd4793fe3
2023-11-27 15:57:11 +00:00
drh 85eafe6f3b Convert the json_tree() and json_each() virtual tables over to use JSONB has
their internal representation.

FossilOrigin-Name: ec18caa3f7790b780dde66c1ccbb6eb09d2f1507629cc45955fc1b08380b4017
2023-11-27 12:36:29 +00:00
drh b4e5bc6cdb All tests passing.
FossilOrigin-Name: b5a5660ca22437640c9bf32c44d92c76a7293dafcbaf4fa6a4c171128d64871d
2023-11-27 12:30:55 +00:00
drh 15c0b03c5d Fix corner-case error conditions.
FossilOrigin-Name: ec23d34ab75e1d7e9366e59c633e0d30def8759f6d4717583ebeb4c90aeccf0d
2023-11-26 00:56:40 +00:00
drh 50b37832b2 Same results as the legacy JsonNode implementation on a small set of test cases.
FossilOrigin-Name: c3da4b079a1a15a4c0b1a6e71f876648b1d9eb32eddc67b9946c2475c7b6d085
2023-11-26 00:48:37 +00:00
drh e09a38c2e8 Remove unused elements from the json_tree() cursor.
FossilOrigin-Name: 914a50117d477b2cd30d58388fb8d1b71ff7ff6842ba025f38efc6e9647d06d0
2023-11-25 23:00:50 +00:00
drh 796abda538 Remove the vestigal JsonNode logic from json_tree() and json_each().
FossilOrigin-Name: 66c2ab9ebbf90477742e6be0d30e061d827c409de038f2a5b73479ed9448c4a6
2023-11-25 20:59:03 +00:00
drh aea2d23121 Almost working. Path is still not exactly right when Root is defined on
json_tree().

FossilOrigin-Name: 92258246916a9c0d72785964513113848a850dec78bdade8b3f274e410df4e7e
2023-11-25 19:28:44 +00:00
drh c2474105ca Generate the fullkey and path columns of json_tree().
FossilOrigin-Name: ffaa468ab8871906121df9ee5ef3dc00129a0086ed9c18831ecda69bf7f71455
2023-11-25 18:11:11 +00:00
drh b7d5cb711a Handle the path argument to json_tree() and json_each().
FossilOrigin-Name: fded888469565b2a4687185a926bd23fccfbf167c8bebe6c10696fc7f972f41e
2023-11-25 13:40:19 +00:00
drh 5e6500c81c Continuing work on json_tree() against a JSONB.
FossilOrigin-Name: 3df891cb11feee65e239ee2506eda34a9688341f05210d7c2e25a05338cb71ad
2023-11-24 21:57:38 +00:00
dan 48cca2422e Add the --buildonly and --dryrun options to testrunner.tcl.
FossilOrigin-Name: a0c87ae9d3db914d18e2c8811db0d0ae3ad7b15c63de84fa975efce28bace27e
2023-11-24 20:14:18 +00:00
drh abbdbdfc1f Incremental progress toward getting json_each() and json_tree() to work
directly off of a JSONB blob.

FossilOrigin-Name: f8cab41b3bc65af6ff34b481db693d640ea025d09463d50b8e56d855e2abc913
2023-11-24 18:44:00 +00:00
dan 88a61ff8ba Allow a pattern to filter test scripts to be appended to testrunner.tcl "mdevtest", "sdevtest" and "release" commands. e.g. "tclsh test/testrunner.tcl sdevtest fts5%".
FossilOrigin-Name: f8ea0b58b37f4052ded448e595d6d2992988a33b8ecfe58d68f20532f8cb5a37
2023-11-24 18:33:40 +00:00
larrybr f5232b3a97 Get all CLI print calls which went to stdout in 3.44.0 to continue going to stdout.
FossilOrigin-Name: e9951ede184ce07cf725152723d795f299922460715ab76225cd3071bf0f18ee
2023-11-24 15:58:14 +00:00
drh ab70266698 Fix jsonParseReset() to properly clear the JsonParse.aBlob element.
FossilOrigin-Name: ab2644aacf4757a51cf62e05cff6711a0a3605d60502a3dd310887df1b993545
2023-11-24 14:25:56 +00:00
drh c0f8d58b21 Omit precompiled binaries from the source tree.
FossilOrigin-Name: 7dbc2f496d7a362460bb4c262ecafe5f30e35a8744861163d12c996365c2142f
2023-11-24 14:03:20 +00:00
drh d47719ee02 Omit the precompiled binary from the source tree.
FossilOrigin-Name: 4ff103d294b79cf7734e87e94e9d88c0e9f0b087cbb352e6da2f0a3a6b268f46
2023-11-24 14:01:56 +00:00
drh ac8b6e70c9 Merge the latest trunk enhancements and fixes into the jsonb branch.
FossilOrigin-Name: a838ebcbbd9f554fd84a1d3176fb572faaef7d0ec0675f1a5bf9430865dafae0
2023-11-24 13:41:20 +00:00
larrybr 77044f30a2 CLI .output/.once to not redirect ".timer on" results.
FossilOrigin-Name: ce766ed51f772a960d0b7a52c113b55c7ae90ef35050496d8e2a77547eab1a4d
2023-11-24 13:26:42 +00:00
dan 226aebae07 Fix an fts5 problem that could occur when mixing regular and secure delete operations on a single table.
FossilOrigin-Name: 8eb3f40021994f0d25ef9d246873796c84886e5951bb8ab991e1e2df31998484
2023-11-23 11:18:06 +00:00
larrybr 5d175eb020 Fix output redirect bug reported in [forum:/forumposts/cbf4933cfeee74bb|the forum].
FossilOrigin-Name: ce542fee6f0150bbd13505dcd26b21a9d1d23eb2dc8e78e63f9da6b4298ec028
2023-11-23 07:08:49 +00:00
stephan a328c42724 Minor doc fix in src/betreeInt.h, prompted by an email report. No code changes.
FossilOrigin-Name: 30d49aaed20454fe006e2f89db58f0c0b2433c99b2676a0b9583f56b7adb7fdb
2023-11-22 22:59:28 +00:00
larrybr 92752a31d9 For CLI build with unused function warnings on, #ifdef out a console I/O function, fPutbUtf8().
FossilOrigin-Name: da36f90d94b3b55de71aa7965421ea850ac677e9e63d60744633c4dc59448de4
2023-11-22 21:24:50 +00:00
stephan c0314bc01d Correct the URL for loading sqlite3-worker1-bundler-friendly.mjs from sqlite3-worker1-promiser-bundler-friendly.js, so that the promiser can be used in bundler-using environments. Problem reported via email.
FossilOrigin-Name: 753a75218913c3b9c7ec5438387107369c34d1775d68b04d19ae18197e558605
2023-11-22 17:11:39 +00:00
drh cf72606a7d Inserts invalid JSONB should return "malformed JSON", not a json path error.
FossilOrigin-Name: 306ee66fbd0231a9f5b229e5630d5cc66c9cf08b466d2d9204e79e1f44a16374
2023-11-21 22:36:32 +00:00
drh 27fea97e44 Direct editing of JSONB using json_insert() and json_set().
FossilOrigin-Name: fffb7a9538838e26991e6f16ea3138346a30c33ea6c3d3834680ee6d1f6eece2
2023-11-21 20:13:08 +00:00
drh e1df37b947 Correct blob-to-text rendering in some corner cases.
FossilOrigin-Name: 7822e0e59f9b611fe6289cc762b0aff61f9b87c3a82c60de110f447589a2c125
2023-11-21 19:05:22 +00:00
larrybr d9f3d6d753 Merge console I/O changes for Windows CLI.
FossilOrigin-Name: 935a8a8ee76d0014df42c1480e044fd1c2dfc26e78abb587d99d861d2ae5eb27
2023-11-21 18:26:06 +00:00
drh 664fe310b5 Fix the translation of JSON5 numeric values from BLOB into text.
FossilOrigin-Name: 40c4fb441f220982e4d61fd42597cf18546791a302fbcc8eec2eed29ee15ef35
2023-11-21 18:23:43 +00:00
drh e97f295783 Merge all recent trunk fixes and enhancements into the jsonb branch.
FossilOrigin-Name: 6d78d50ed2357e6c943c1ef97b1d2ea0902cbadef90c2c35dccdbdc2bdf8702f
2023-11-21 17:54:55 +00:00
drh 8a4cecaea2 Make edits directly to the JSONB BLOB when the input to json_replace()
is a JSONB.

FossilOrigin-Name: d69c6acef54a81f46a97a05d443fe648635b4b70772069d6705ef829b718e985
2023-11-21 17:51:58 +00:00
larrybr e788255681 Sync w/trunk as pre-merge-to-trunk sanity check.
FossilOrigin-Name: 448d6a1182d29940d5d34be2ce67df5601b688cd902dbbe97e95073f982a49ce
2023-11-21 15:55:31 +00:00
drh a4050f1434 Fix the trace3-4.4 test to be more rebust against timing quirks.
FossilOrigin-Name: 8936daa08243729d8538bb7288bbefb43f3bd842a0d4b2e8019092f5701c2926
2023-11-21 12:02:04 +00:00
drh 4f77a27032 Back out an incorrect change to the sqlite3ExprCompareSkip() function that
was added way back on 2019-08-22 for [44578865fa7baf97|check-in 44578865fa7ba]
and which was only today discovered to be incorrect by
[forum:/forumpost/45ec3d9788|forum post 45ec3d9788].

FossilOrigin-Name: f5b3eb0fc8936ba274a7654ff6dfa7d4654bd8dbca7f3a5ec1134b0b5260d59d
2023-11-20 15:54:00 +00:00
drh 0fcaf16f20 Convert an assert in OP_VCheck into a branch that aborts the opcode, as this
can happen on some very obscure conditions, as discovered by dbsqlfuzz.
Test case in TH3.

FossilOrigin-Name: 7946c79567b0ccd3a00d12390e99896d7dc11407d0b52bc39338a16a493f56f6
2023-11-20 13:06:59 +00:00
dan 56bb07bad6 Fix an assert() in fts5 that could be true following an OOM or IO error in contentless-delete mode.
FossilOrigin-Name: 3fe89238c31ca163d021ef1fecde594328815aaba7053fef9e9c789562a62f45
2023-11-20 11:40:18 +00:00
larrybr 033127af75 Cherrypick shell1.test fix.
FossilOrigin-Name: 91c888eddbcb1b461f7d562c2f0eee57f1a2be7f9959b9d69e80fc7c1da20e9e
2023-11-20 00:21:24 +00:00
larrybr 4c9a02c9f0 Cherrypick shell1.test fix.
FossilOrigin-Name: 39e30c5f9cc6dcac003255734e3ce1ac5b05349ea1a25e1c108b5f6d1d97612b
2023-11-20 00:20:56 +00:00
mistachkin 73e3e0c21f Correct conditional compilation issue seen with MSVC in the Win32 mutex subsystem.
FossilOrigin-Name: 6f8f4bfe607f1405d313bb88a33490621002f63e8c02c980f4c083630ad3a6d2
2023-11-18 18:36:26 +00:00
dan 046a7f9493 When ENABLE_SETLK is defined, avoid ever blocking on the lock mutex in os_unix.c when requesting an exclusive lock.
FossilOrigin-Name: eb36d475e91bfdbf4a18b6fd9751fbcecf15d960dcd1c00d2d18b5bf1d7503fe
2023-11-18 17:20:04 +00:00
drh 52c41ed41b Adjust an assert() in fts5WritePoslistData() so that it only applies if there
have been no prior errors.
dbsqlfuzz 25dca9b2568f67dc78a0e32ff280133fe71994bd.

FossilOrigin-Name: 257cdbab90c6db8ccc9a8fd5df556b69c3a35a329d39cd4642c792d7359a54a5
2023-11-18 12:06:21 +00:00
drh b8688e131e Another assertion fault fix, similar to [a9443dbfbe25e588]. dbsqlfuzz
2d9af4e94aca188e0092900eec711401c5d51687.

FossilOrigin-Name: 3afaeac56dff58db596360bf6f8dca97cb31405f73be8e189e8c0e6a1e5b239d
2023-11-18 11:23:01 +00:00
dan 11c512d631 When SQLITE_ENABLE_SETLK_TIMEOUT is defined, use a separate mutex in os_unix.c for each shm locking slot.
FossilOrigin-Name: 64691df980cdf73ddc00aabe15baa6c018e1d76b0e87f55ab33a9348fd5680bd
2023-11-17 19:01:38 +00:00
drh f9ae48b9ed Add the new "run-fuzzcheck" target on the autoconf unix makefile. Requires
that FUZZDB be set to the name of the fuzz-data database file.

FossilOrigin-Name: 8fa3915dbfdd9a5b0fcf4d695590b3de7e7d19d2917924186ca889cd60bf0eb9
2023-11-17 17:55:03 +00:00
drh 003d419b33 Add an assert() to prove the sqlite3_prepare() always either returns
SQLITE_OK or else leaves *ppStmt set to NULL.  See
[forum:/forumpost/70bb8576c6c084c2|forum post 70bb8576c6c084c2].

FossilOrigin-Name: feadd4024228e578811447c4b2d2b60780ff3d3681f80ca903585aa7b289d758
2023-11-17 17:25:30 +00:00
dan 735e7ee62a When SQLITE_ENABLE_SETLK_TIMEOUT is defined, use a separate mutex in os_unix.c for each shm locking slot.
FossilOrigin-Name: 4098df9652d90f2d22d5591d915d672c5413471f7916223510ba6fd932bfdd36
2023-11-17 17:10:37 +00:00
drh e416251725 Merge the latest trunk enhancements and fixes into the jsonb branch.
FossilOrigin-Name: 162f0509ef27bcd3ec87629640281a71c773e7c3bbd2cd0df76faf481531e7f1
2023-11-17 17:03:45 +00:00
drh f2bb6ab3fb Fix harmless compiler warnings in debugging code.
FossilOrigin-Name: ce6a75622ea5bca517bc6613e738aa670c9e1dd863596220eded5c2379c616c7
2023-11-17 12:22:42 +00:00
drh c15133e82a Fix an incorrect assert() associated with ALTER TABLE where an unknown
aggregate function contains an ORDER BY clause.
dbsqlfuzz e0900262dadd5c78c2226ad6a435c7f0255be2cd.

FossilOrigin-Name: a9443dbfbe25e588b4adddde664ddf482f19f71c704fbf356d49cf3a6135e7fb
2023-11-17 11:58:26 +00:00
larrybr e1edecf5d3 Simplify and make more rational how console I/O package features are selected. (Motivated by Fiddle and other command-line utilities to soon use the package.) No substantive code-execution changes.
FossilOrigin-Name: 1cde05877b7e47cb2ab9de26edd5245eb5ff1d91e69b94f3b24944fd4f6ccd3e
2023-11-16 18:31:05 +00:00
drh 11e8242e2e Both json_remove() jsonb_remove() work on pure JSONB as long as the input
is JSONB.

FossilOrigin-Name: 68d551730be0a3ea9579646ed4836c73554c83ca7f2303b69a18843f1750f1a7
2023-11-15 20:32:06 +00:00
drh 5e3ae1ec76 Some simple test cases for JSONB direct remove.
FossilOrigin-Name: 8cb4d2cbfc1b5f3c612d85138e66da8735d6589c7538fdf494a761c9b8104f18
2023-11-15 19:21:09 +00:00
dan 91c8e65dd4 Changes so that if SQLITE_ENABLE_SETLK_TIMEOUT is defined as 2 instead of 1, all blocking locks are taken for a single millisecond and the default busy-handler invoked as normal.
FossilOrigin-Name: 79e24ec3dd40373bbb93792829b18d9ef40daf19d4606174e36c8e19e61a7529
2023-11-15 19:19:04 +00:00
drh 8c96d3c104 jsonb_remove() now works without having to use a JsonNode parse, assuming
that the input is JSONB.

FossilOrigin-Name: 5207679e929786e577a0553d0d84dda5125456dcde80c0f3156f14f4d8c804cb
2023-11-15 18:55:03 +00:00
drh af0c9ffb4a The jsonb_remove() routine now appears to be working.
FossilOrigin-Name: e76d48137ea823b7810dc8c3b70eb21adabdd6cfbac36050c85d1375e94be1de
2023-11-15 18:47:31 +00:00
drh 0399994759 Work toward getting jsonb_remove() to work directly on JSONB blobs.
FossilOrigin-Name: a79ff8e58fcaf718a6fb78e145117f1d6d40d133f31e9752bb9c6d484850a27b
2023-11-15 16:10:31 +00:00
drh 9eb7694d58 Improvements to the description of sqlite3_errmsg() and sqlite3_errstr().
FossilOrigin-Name: fe5cc4169c5348324e863d3e339de94ed01749a3b9c86aa9adc5e3244bd9d033
2023-11-15 14:09:37 +00:00
drh fb57c8a932 Merge all the latest enhancements and fixes from trunk into the jsonb branch.
FossilOrigin-Name: ba91408f4c044feda003ef93784ccefb619f99ab64379ced481ee8e9e890fd41
2023-11-15 13:23:40 +00:00
stephan 5cc4ab93f2 Fix an exception misuse in test-opfs-vfs.js.
FossilOrigin-Name: 9264955e6e47aa8fc3a6f8bed192a6c12f43de49f7fba2e0cc080e47abedde14
2023-11-15 11:31:49 +00:00
stephan 1b963102b7 JNI: add more wrapper1 Sqlite.Blob tests.
FossilOrigin-Name: d63f6e1ffda9a88a37acc7862cb7ee8b9cd669b0fdba64c1ec9dd221cf807714
2023-11-15 08:59:53 +00:00
stephan bd06d8672d JNI: clear out the sqlite3_context native pointer after calling UDF callbacks which do not have an argv (as was already done for those which have an argv). Add related tests and code commentary.
FossilOrigin-Name: 138f40543b26b2e02e27d830d92e30b12cfef5a8dc3f0b58b39c68e1b3c91cc6
2023-11-15 08:29:42 +00:00
stephan 4d6b10cdbe JNI doc updates.
FossilOrigin-Name: 1b1f36a206319e99ccaed969893ff95dcf3b8e97ed301544cf3cd3fee2780335
2023-11-15 06:28:51 +00:00
stephan 6b36312e8a JNI: add the @Experimental annotation and mark all java.nio.ByteBuffer-related methods with it.
FossilOrigin-Name: 0f4b223102e5dc9142c9d2cb8892b8d3cc476e579420028b93d4e12f4cf94d3e
2023-11-15 06:10:37 +00:00
stephan 973011432b JNI test code cleanups.
FossilOrigin-Name: 09142ac14347e6f41bbe50bc835920e271713452733a478ede547816cc291ace
2023-11-15 05:08:39 +00:00
stephan d7ef0e8f87 JNI: add CONFIG_LOG and CONFIG_SQLLOG support to wrapper1. Code-adjacent cleanups.
FossilOrigin-Name: 83c49b9e71e5ae8852bab60a6fa630e22164c8efbf074c85450136781d0fffd3
2023-11-15 04:55:38 +00:00
stephan 253727b33d JNI: apply an internal level of API indirection to avoid having to work with massively-mangled names for the various sqlite3_config() overloads.
FossilOrigin-Name: 24f20663b1c4e13ff7d9a89e1df6af2e6f5730e5042ae6479e0a8c1bb846f313
2023-11-15 03:02:11 +00:00
drh 7df044633d Add NEVER() to a branch made unreachable by [6f9eed826f5b3d1c].
FossilOrigin-Name: 26dcaa34e3521783bde687749d590eca54cecb4bb95ef332a4a6473c4141d052
2023-11-14 16:53:52 +00:00
stephan 5d59669711 JNI: reimplement Tester2.execSql() using the high-level API.
FossilOrigin-Name: 3a69679e41d23a760df349b2471a1ed306c087f9a7a7a2e2cba3723071dee6b2
2023-11-14 14:59:41 +00:00
dan d928e78088 Fix another obscure problem with nested aggregates. dbsqlfuzz 04408efc51.
FossilOrigin-Name: 6f9eed826f5b3d1cb08402925b406a7fe9b54259af1ba5eba92d4d37fbad628a
2023-11-14 14:50:34 +00:00
stephan cb3a0b1b67 JNI: add Sqlite.Stmt.step(boolean) overload which returns the result code of sqlite3_step() unless passed true, in which case it throws for any result other than ROW or DONE. The intent is to simplify handling of LOCKED and BUSY errors.
FossilOrigin-Name: f4f1cc201a7dc618a66617778ecf58ba60461ae700cb41f5c4abfa26dd0c0ed4
2023-11-14 14:38:11 +00:00
drh 34ccd18d65 Extra PRAGMA vdbe_addoptrace output showing when OP_Column gets translated
into OP_Copy due to using a coroutine instead of a cursor.

FossilOrigin-Name: eba180e77977acd6f3d4a0e3c99a2ebd4ce2839e9ce30c588929e36d69aa762a
2023-11-14 13:51:19 +00:00
stephan 4ce5bc2836 JNI: use ByteBuffer.limit() instead of ByteBuffer.capacity() when figuring out where the logical end of a ByteBuffer is, for reasons explained at length in new code comments. This is unfortunately slower but is the correct way to do it.
FossilOrigin-Name: 51539419edc08ee6c70d8719d0f4d5ad47dd545a7fd9bf01d03a434aabd41d68
2023-11-14 05:33:44 +00:00
stephan bdfc51dfef JNI: add sqlite3_blob_read_nio_buffer() and iron out the blob/ByteBuffer interface somewhat.
FossilOrigin-Name: 7df317b448a09ae77e2c68cc901fdb6d56a2246c1313f06bebd1f3e53f02c19b
2023-11-14 04:59:57 +00:00
larrybr f695620e46 Add a few asserts into *Put*() functions to catch calls that might cause an address fault.
FossilOrigin-Name: 2341f9b6a48634a94e90e849f579afd07d398c3e0304efccf07d18b41a0e40aa
2023-11-14 03:24:43 +00:00
stephan adcd13d243 JNI: change sqlite3_prepare_multi()'s exception-handling semantics to be more C-like and, to support that, add the package-private sqlite3_jni_db_error() method to set the db error state from package-level Java code.
FossilOrigin-Name: 46656b354311ec0a36832af1c4ccb3b6a244aa55cfb3681e25c3f42b13b387dd
2023-11-14 02:43:30 +00:00
stephan b481413d95 JNI: add sqlite3_blob_write() overload which accepts a java.nio.ByteBuffer. Cleanups in adjacent code.
FossilOrigin-Name: ca32af8542aa2725cc87f54541b19897556f610e4674edf9f22a84e3d4097a82
2023-11-14 01:33:15 +00:00
stephan ce2edab088 JNI: add sqlite3_column_nio_buffer() and sqlite3_value_nio_buffer() using an only-slightly roundabout approach to creating properly-sized ByteBuffer objects.
FossilOrigin-Name: efbc82b218d26b7ca9b881da69d5fd14d22b5211fbd85a835da50e5bfde3d160
2023-11-13 23:11:10 +00:00
stephan 87c407da18 JNI: add sqlite3_result_nio_buffer() and tests. Discover that we cannot create sensible sqlite3_column_nio_buffer() or sqlite3_value_nio_buffer() counterparts because of ByteBuffer interface limitations.
FossilOrigin-Name: 44b4df01ff86841fb85b6295cbada422c6ba8a32a420a2e840e2d607b6c90164
2023-11-13 18:35:37 +00:00
larrybr 5ed4ba0f7d Cure many warnings from gcc, clang and CL.exe.
FossilOrigin-Name: 29ea2a3aadd34facc45a2e9f9a567bac16fca76beb019b879e2611433c85bbb3
2023-11-13 15:59:27 +00:00
stephan 7f7d7bea01 JNI: add sqlite3_bind_nio_buffer() and initial tests for binding ByteBuffer objects as blobs on JVMs which have JNI support for nio buffers.
FossilOrigin-Name: b10ce1ef82d84726fbf6a8f624d6530f84fefb505f7868b4a0ea910fed7a877f
2023-11-13 14:58:37 +00:00
larrybr 41d4b7bdee Fix var-intro after executable code departure from old C.
FossilOrigin-Name: 08996f4fd52f5742e77225ce3da2ac43ea5cc44bb0d8d21126b6d624273842a5
2023-11-13 13:01:01 +00:00
larrybr c270dad95d Slight cleanup of length-limited strpbrk() replacement, and eliminate strpbrk() call.
FossilOrigin-Name: 97e2c9621e3e01048e33da63ca4146ededa33cf6adefa996fa49b8c6a8d555b5
2023-11-13 12:53:47 +00:00
larrybr 14a08730de Enhance console_io to permit emits limited in various ways, such as valid UTF-8, upto control chars, or with counted limits, all getting away from 0-termination as the sole limit. In CLI, use this capability to avoid certain emit-chars-singly procedures that were breaking up UTF-8 characters. This fixes broken json mode output (on Windows) and (maybe) C-literal-like emits.
FossilOrigin-Name: 906c5c4082e30b7a0d07df89a42566461e2113507c5a0b339827ca0822b8fe84
2023-11-13 05:24:00 +00:00
larrybr fdbd9119d4 Add sqlite3_x86.exe unversioned binary.
FossilOrigin-Name: a731cdddbb99dbd3f9d1875cad5094239b78969c84fe4c56ecd63e33a5874e3f
2023-11-12 19:57:23 +00:00
larrybr 782c9f2e9e Use setOutputStream() to designate implicit output for oput{z,f}() emit functions, and use them extensively.
FossilOrigin-Name: 7850fb98a19d0ae3535367de3bca9e50408a2c21504c5772947fc39f287aa830
2023-11-12 03:58:15 +00:00
larrybr cc2b3c2051 Write BOM without fwrite(), using sputz() so that if it goes to the console, it is translated "properly".
FossilOrigin-Name: 06ef96a8233c6b6ca2653a0b780b3a401cab2b77594125f4f1c54b269c22a9f9
2023-11-12 00:43:36 +00:00
larrybr ea80462c10 Remove SHELL_LEGACY_CONSOLE_IO PP symbol and code it made active. (It is in the repo if ever needed/wanted, but it is just inferior or dead code now.)
FossilOrigin-Name: 27c5bf6563bc24ba7b47865e8d2f3e2d439666e19038d86dd8445fcdb9abe97a
2023-11-11 22:53:55 +00:00
larrybr 1bcb7c4902 Complete shell transition to using {f,o,e}put{f,z}() emit functions. This fails test 13.1 in json501.test, but so does trunk in the same way.
FossilOrigin-Name: 923c6b8b3a508c715b816c6bcd2ae9ac519bc37a62afc4ef813085c00f1e7cb6
2023-11-11 20:46:12 +00:00
stephan 56e1610f7a JNI wrapper1: when checking for an out-of-bounds statement column index, perform the is-statement-finalized check before the range check so that the former exception trumps the latter.
FossilOrigin-Name: 0832f9a8e9f574b157c791c5cddc73aff7b2ff403509f5d78f310494d4a7f93d
2023-11-11 14:50:01 +00:00
stephan 307f95c1e4 Do not cache a statement's column count in the JNI wrapper1 API because an ALTER TABLE via another statement may invalidate it, as reported in [forum:6d80efd58d4591c7|forum post 6d80efd58d4591c7].
FossilOrigin-Name: a6ab88e9a67f23ab7885402776282b94033cb48dbe34d4d18356e4dc22aae7cd
2023-11-11 14:43:50 +00:00
larrybr d2c8658024 Fix malf with redirected input due to bad assumption that stdin is a console in the fgets() replacement.
FossilOrigin-Name: 79d1f2c1019964dd154fbdd3f349822cb946a2600883994523ed145047f0a9ea
2023-11-11 13:09:09 +00:00
larrybr 1229f8e6bd Pervasive changes to console_io.{c,h} in support of simplifying ubiquitous emit ops in shell, and to get better control of console streams that might be opened only via .read or .output commands. Changes to shell to use {s,o,e}put{f,z}(...) calls for initial testing, but this check-in has few such conversions so that most will be in a separate check-in. Many renames to better follow recent coding convention. This code seems to be working, but has not been tested on difficult platforms or with multiple console hosts yet. So it is a WIP.
FossilOrigin-Name: 14762a004cdf37d1e12f26aadff8ed3824893278f22ff141de86dd44d9b250f3
2023-11-11 06:20:38 +00:00
dan fb28a93f75 Fix another problem with mixed join types and the RIGHT JOIN strength-reduction optimization. [forum:/forumpost/befdab472d | Forum post befdab472d].
FossilOrigin-Name: f1eae192315335d7e385b0a801a17700a9718d245bda6628518c5df9a1e9d3d6
2023-11-10 20:55:20 +00:00
drh 88dcfe56da Additional debugging information on the tree-dump of the BETWEEN operator.
FossilOrigin-Name: aca31e49d1d25043769544ccf2a07980c5f162a8eb2486e393bf9d9d1a394a60
2023-11-10 20:46:58 +00:00
drh 10c815a55d Remove an incorrect ALWAYS() that was inserted yesterday [1e039b6eb59c0001].
FossilOrigin-Name: 12885e298b9d3f977f1de11a194692dfb5fbb7daeabd958674f884a5575ddd24
2023-11-10 20:35:59 +00:00
drh e8d4fd59e4 Merge recent trunk enhancements and fixes into the jsonb branch.
FossilOrigin-Name: 091a5f058dfe2115fb9213655b34f00bcec80aebb299b571975cfe4ecd5ec206
2023-11-10 18:59:23 +00:00
drh 5a81e6e5ce Ensure 8-byte alignment of data structues in sqlite3_database_file_object().
This should have appeared on trunk originally and then be cherry-picked onto
the branch.  Oh well....

FossilOrigin-Name: ac39800bb2685fa287c7d834faed75f0bc61320ef986de314392d6eadb574d30
2023-11-10 17:49:26 +00:00
drh 53381132be Remove a NEVER() from whereAddIndexedExpr() that is reachable if there
is an unknown indexed function in the schema.

FossilOrigin-Name: a976b7208ff8603d7353ce9a0bdfba8e681cbb2ed3de6cfb5f0e8b07312ab86f
2023-11-10 16:29:02 +00:00
dan 0eed27d38b Fix an obscure problem with the join-strength-reduction optimization that could occur when mixing LEFT and RIGHT joins in the same query. [forum:/forumpost/7f74ce0bee|Forum post 7f74ce0bee].
FossilOrigin-Name: 530d10e93a5f63b71aaa94a2b89102d012a2cda815997066beb0f585fe823536
2023-11-10 15:03:18 +00:00
stephan 9d60c3c256 Expose the missing SQLITE_SUBTYPE to wasm.
FossilOrigin-Name: ac9534b2ceb8185b1fc03282f881cd3e4aea64af75a02ebded1e07d4d8278739
2023-11-10 15:00:26 +00:00
stephan 828a00c287 Expose the missing SQLITE_SUBTYPE to JNI.
FossilOrigin-Name: 0f92f4c90eb9397325f1a86836e356862108e2e850c1801e0bec4a7030dea271
2023-11-10 15:00:11 +00:00
stephan af65e7d21f Expose SQLITE_RESULT_SUBTYPE to JNI.
FossilOrigin-Name: 3bf75875b8be8d2e878681506fb35f2062d59f07fa23f571c58cd92f270bb197
2023-11-10 14:15:07 +00:00
stephan 6db0b11e07 Expose SQLITE_RESULT_SUBTYPE to wasm.
FossilOrigin-Name: 6d2fe9848beb35a8206e49c2ffae29a3eb2fe6411d77f366e962ced3f83e4749
2023-11-09 17:53:44 +00:00
drh 3839dcf973 Add the SQLITE_RESULT_SUBTYPE flag for application-defined functions. Add
the -DSQLITE_STRICT_SUBTYPE=1 compile-time option that raises an error if
any function invokes sqlite3_result_subtype() without the SQLITE_RESULT_SUBTYPE
flag.  SQLITE_RESULT_SUBTYPE prevents an indexed value of that function from
being used to replace an equivalent expression, since the indexed expression
does not carry the subtype.  Fix for the problem described at
[forum:/forumpost/68d284c86b082c3e|forum post 68d284c86b082c3e].

FossilOrigin-Name: ba789a7804ab96d81b15d6ef6fed1f802fa69db47cf91d368933e55289fa1d6e
2023-11-09 17:36:37 +00:00
mistachkin 2009a5acba Fix compilation issue seen with MSVC.
FossilOrigin-Name: 0dfe790d8118ff1bacc9e7c97d4f8ff9e5789f6cda8ec6fd981ea38b4da3905d
2023-11-09 17:28:31 +00:00
drh beb06e6b0a Put an ALWAYS on an true branch.
FossilOrigin-Name: 1e039b6eb59c0001a9efdd2f9928a34d4e9e01972ee76aa04a1279369dc03840
2023-11-09 17:26:39 +00:00
drh cb1f190ed2 Futher documentation refinements.
FossilOrigin-Name: 311c2eba93097bbecfa286bbeaff9bd6fc75a238e20cd2b6f834e594032d8c59
2023-11-09 16:52:44 +00:00
drh b10c3d32e0 Fixes: (1) In the ->> function, instead of setting a subtype and clearing it,
do not set it in the first place, as doing the set would trigger an error
under SQLITE_STRICT_SUBTYPE.  (2) Allow the SQLITE_STRICT_SUBTYPE through
the property filter on sqlite3_create_function().

FossilOrigin-Name: 6195468b14f6f17ea072cf191c9ef1bd0713acd314bc6dc128be7322bfd612cc
2023-11-09 15:01:56 +00:00
stephan 752722e8d1 A .class file build dependencies fix in the JNI build.
FossilOrigin-Name: 8cc32915165efd7c261f008bb6fa4cc6581ee7bd73ea5da47513742b9e6d34e4
2023-11-09 13:00:33 +00:00
drh 6eb381ff4a Add the SQLITE_STRICT_SUBTYPE compile-time option. This change reveals that
the current SQLITE_RESULT_SUBTYPE design does not work unless we tag the ->>
operator with SQLITE_RESULT_SUBTYPE.  But that will disable an important
optimization.

FossilOrigin-Name: e98a9a65dd309f72c240e280c7bebabc58af664fae9ee0d30c3fa1c78db5bae9
2023-11-09 12:58:03 +00:00
stephan b9050dcec7 Add some notes about the JNI pointer-passing approach and convert a couple of potential NullPointerExceptions into appropriate C result codes. Clarify that invocation of undefined behaviour from the Java API does not (due to the addition of defensive code) mean the same thing as it does in C (e.g. no NULL pointer dereferences).
FossilOrigin-Name: 19c4778f45261006368b2d9460350fed1e55fed314c8b3e1af34cd8c3c73b7d8
2023-11-09 12:48:54 +00:00
drh b18bb822dc Do not replace expressions that return subtypes with values taken from an
index.

FossilOrigin-Name: a35d13db09e32ee339f3983fe36b073714753ee3d39f577ae8d20596d7adc3eb
2023-11-09 12:17:57 +00:00
drh 194b8d514b Omit the new SQLITE_VALUE_SUBTYPE name. Stay with legacy SQLTIE_SUBTYPE.
Add extra documentation to sqlite3_value_subtype() and sqlite3_result_subtype()
indicating that the SQLITE_SUBTYPE and SQLITE_RESULT_SUBTYPE properties are
required on functions that use those interfaces.

FossilOrigin-Name: 563ad3be60d22c45f1c5b9a3e67738593f8b38f137147c56514166fbabf95365
2023-11-09 12:08:16 +00:00
stephan ec427813ac Two more JNI build fixes for Windows/MinGW, reported in [forum:4f949edc312d2a75|forum post 4f949edc312d2a75].
FossilOrigin-Name: a3f9c39086e582e16ca15647961956b3c28d038655d3b43d4b94bd306fbec1a4
2023-11-09 12:01:02 +00:00
drh c060b5f3a8 JSON5 bug fix: Escape double-quotes that occur inside of single-quoted strings.
[forum:/forumpost/ddcad3e884|Forum post ddcad3e884].

FossilOrigin-Name: 1c98d46d60ef1494bd8b7561c7d0cd5aafc178201a6f1f0da25dea6140b91cd0
2023-11-09 01:54:26 +00:00
drh 243f2ec6a1 Make a distinction between functions that consume subtypes and functions
that generate subtypes.

FossilOrigin-Name: 48a92e3ad855227188a4c5afe4abbb7171761cf6fc930660084d9abeecfd91d9
2023-11-08 21:38:30 +00:00
drh 2cbe14098b Do not cover expressions using an indexed expression if the indexed expression
is a function that might set a subtype.

FossilOrigin-Name: e908b26a990929996b3c16f0429e8313cd8fcefe7c883c77f66ea69f4059d6e2
2023-11-08 18:08:07 +00:00
drh a4cf38ca9b Merge recent trunk enhancements into the jsonb branch, and especially the
finer-grain characterization of JSON function properties.

FossilOrigin-Name: 72393b003f9f8675e4a124dddd09607b5b34ddefe56716b283c68c0982fb3d96
2023-11-08 17:11:13 +00:00
drh b494366370 More precise characterization of JSON functions. Indicate when functions might
return JSON (subtype 'J') and when they make use of the function argument cache.

FossilOrigin-Name: b2b62546c4a5e9dccb8aa0cb8eda228d662c69159e320b01a377317bc909e89f
2023-11-08 16:37:12 +00:00
dan 6234b33478 Have the shell tool emit a warning if the user attempts to use ".scanstats vm" in a non-SQLITE_ENABLE_BYTECODE_VTAB build.
FossilOrigin-Name: 3978c084a509c3c739fbe87e20feec9ddf1325e35170329987af197ca9fd731a
2023-11-08 15:56:41 +00:00
dan e445586630 Remove old files related to wapptest.tcl from test/ directory.
FossilOrigin-Name: dd3e7b5bcad122ac1e7e19ec547f4486ce90a6a2aa89a64e36bea13a216492fe
2023-11-08 15:51:42 +00:00
dan 0ad5301378 Avoid blocking as part of passive checkpoint operations, even if SQLITE_ENABLE_SETLK_TIMEOUT is defined.
FossilOrigin-Name: e5ecc404cae1ce8b639d0263fa07571c066f11bfc62f5ba331ad7ae138e78572
2023-11-08 15:49:57 +00:00
stephan 8657eddcdb Remove an unused/invalid test from the wasm suite.
FossilOrigin-Name: 916ae898743a969295a48ae2a6e9e366586834b32d77d3fa281bbaf7f2818502
2023-11-08 15:34:03 +00:00
stephan 86b1898cb4 JNI build fixes for platforms where the jint type is not the same as int, as reported in [forum:9089d2049a|forum post 9089d2049a].
FossilOrigin-Name: b32b0873274bfe472114da8a308a04bee76ba26a5830d8d04fc921f9c1544f9d
2023-11-08 12:56:23 +00:00
drh c78d3b5963 Suppress harmless UBSAN warnings about memory overflow in OP_AddImm. The
exact same machine code is generated by GCC.

FossilOrigin-Name: b0594383b9fa021a8713d640a4606b9053f8e21d64b4ec8ea60a0b6cddfca306
2023-11-08 00:45:14 +00:00
drh ec8f893e06 Changes a no-op call to freeP4() into an assert().
FossilOrigin-Name: 32a7b1bd4d88a6839c2c5061a38b4a28f31b22aa8fa08c743633ff96fc4bf88d
2023-11-08 00:12:38 +00:00
dan d7b0b5ec6f Add -DSQLITE_ENABLE_SETLK_TIMEOUT=1 to a release-test configuration.
FossilOrigin-Name: cd3e38fb0f2f7e134bb6cfbe86b6621017344e4361dc6a09ec1367860ba8773b
2023-11-07 20:56:29 +00:00
dan 275234e320 Fix an assert() that could fail within calls to sqlite3_snapshot_open() in SQLITE_ENABLE_SETLK_TIMEOUT builds.
FossilOrigin-Name: 84634bc268e5c80146f3f3b2e13118f239c9a7e4e4e9dfcaccef2b17252ce53b
2023-11-07 20:11:49 +00:00
stephan 344255e5aa An attempt to work around compilation errors on MinGW reported in [forum:9089d2049a|forum post 9089d2049a].
FossilOrigin-Name: d5658a3ee4f585cc1e96d84425aad2e1f56b3ae507c9e17b71e030f83f0b70e8
2023-11-07 19:39:23 +00:00
larrybr 73f03276d9 Refactor MBCS/UTF-8 translation to avoid extra allocations, supporting non-formatted (faster) output. Some code cleanup. Wrap .system/.shell command exection with restoration of startup console mode and renewing mode setup. Changes to make legacy MBCS build work better (than legacy did, even with --no-utf8.)
FossilOrigin-Name: d5e88fcde53ca7ba05bb164943a9f57bd92080bb7e5eebbbed64b9886ac97338
2023-11-07 19:30:14 +00:00
drh 17a3295387 Update the documentation to the sqlite3_set_auxdata() and sqlite3_get_auxdata()
routines to make it clear that they do not work as one might expect when they
are called during query planning, instead of during query execution.  The JSON
routines misuse those interfaces, so add a special flag to JSON routines that
prevents them from being invoked during query planning.  Fix for the problem
in [forum:/forumpost/a655ee159eca1ea5|forum post a655ee159eca1ea5].

FossilOrigin-Name: 796a23f9ee33da0803844a2f40c1733db894cc4ef7fbaa1fa94af6af2d3b873b
2023-11-07 19:03:13 +00:00
stephan 637922acac JNI: during static init record whether the current JVM supports JNI-level access to java.nio.ByteBuffer raw memory, and add sqlite3_jni_supports_nio() to query that.
FossilOrigin-Name: fb8dbb77a4d8efafd6772333824b4ab589828cf155a63ca6a26730314d0a4bd9
2023-11-07 17:15:55 +00:00
stephan 488125d4ce Add Sqlite.prepareMulti() to JNI wrapper1, for preparing multiple statements from a single input.
FossilOrigin-Name: e4670d68b52233ab376a1725983e148aaf2a2c3658a41f5768e37a0f1f87428a
2023-11-07 15:56:39 +00:00
stephan 6dc368e632 Diverse minor cleanups in the JNI pieces.
FossilOrigin-Name: 35233dd900632b997b5e532170a3b2af0ca7f1dccb8407555b93f2b395b0f7b4
2023-11-07 13:44:29 +00:00
stephan 6ca0cfd87a Flesh out [7a63b5b65a79] to be able to build JNI with or without SQLITE_ENABLE_COLUMN_METADATA.
FossilOrigin-Name: fcee41b3d4d2558299ead28cc17f290b9ff1957a84c3feaa0a24872feeb22901
2023-11-07 13:22:49 +00:00
larrybr 4c78cb50bf Get dependencies into make recipes. Get legacy console I/O (-DSHELL_LEGACY_CONSOLE_IO) working. Due to movement of MBCS/UTF-8 translation into traditional stream I/O simulacra, the input translation does not happen the same way. (It works the same, but fails differently and a bit better.) Added printf() and fputs() look-alikes, and made CLI use them.
FossilOrigin-Name: 1721dc6a434361c4e2b87c6e677b6dc223432b3cdd5b9eecabaa258889fb2d2a
2023-11-07 02:41:46 +00:00
stephan 23056b608e Add -DSQLITE_ENABLE_COLUMN_METADATA to the JNI build, as per [forum:9205518c0568fdf0|forum post 9205518c0568fdf0]. Add tests for the functions that flag enables so that the build will fail if that flag is missing.
FossilOrigin-Name: 7a63b5b65a79d15658a160d0878c7371941c67e9b48a7442762c68c60b77288a
2023-11-06 21:57:15 +00:00
dan a3e8822c4b Fix an fts5 problem where a transaction consisting of (a) a DELETE on rowid X, (b) a prefix query, and (c) an INSERT on rowid X, could corrupt the index.
FossilOrigin-Name: c2058a045b57571b2b5d342adb212fe606717c633a0422755691ae6bf5725d25
2023-11-06 18:40:25 +00:00
larrybr d0046388a0 Move console_io lib to its own subdirectory, etc/consio .
FossilOrigin-Name: 1d0583f2eb69fdca1cbc55763c0e86a7e32cb7771bfbc2cdf02da4e3fedbfa23
2023-11-06 15:31:08 +00:00
larrybr eb1898d6f3 Some renaming, warnings cured, and more coding convention conformance.
FossilOrigin-Name: 58815f0ad259599a674e7d0fe0d4676a1c4fb8e118c08b619580ff655fb3be40
2023-11-06 15:15:58 +00:00
larrybr 56fba47850 Add an fputs() equivalent to console I/O lib, and use in CLI.
FossilOrigin-Name: d661f90724b1bd31948169841bacb80ba4ae91b52191a0b0021a89a22d932a02
2023-11-06 13:24:07 +00:00
larrybr e3a6a60901 Cause CLI to use console_io library.
FossilOrigin-Name: bf66a7c1d330b04fd3c3e50f43ebe1e41307db59d7189798acafb3de77e0c8b2
2023-11-06 03:09:10 +00:00
larrybr a0cd392979 Make MSVC accept it, too. (Cannot use static const int as part of a constant expression?)
FossilOrigin-Name: bb278d2496b27d2e2ee3cedd6fc54394e71ab2ba5d3d51593f97e897b8b306a4
2023-11-06 00:15:14 +00:00
larrybr 8dd4697e48 Make it buildable. Pull test program from testee. Zap stray fprintf().
FossilOrigin-Name: 2b850aca1e76805a0358064318a765fa66ce394d015936fd47683d74ca4c187e
2023-11-05 23:55:41 +00:00
larrybr ff39634625 Input working. No line-editor provisions yet. (WIP, but suitable for testing.)
FossilOrigin-Name: e8568b1d925c2118eb08394dd8aa50cfb521240f87668f535ec4a03e67dc9a09
2023-11-05 19:42:00 +00:00
stephan ed99e7493a Add incremental blob I/O support to JNI wrapper1.
FossilOrigin-Name: 7f1c76fe930d69a0274f70fa7b7e68e0db6226b731a065fa57d0936c8400ffb0
2023-11-05 04:20:04 +00:00
stephan 546db3f14a JNI wrapper1 normalizeSql() now throws UnsupportedOperationException, instead of returning null, if built without SQLITE_ENABLE_NORMALIZE. Remove SQLITE_PREPARE_NORMALIZE from the JNI interface because it's a legacy no-op.
FossilOrigin-Name: d081a126697e214082f3b203f23ea63510080e5c2aac1d8badc9e6e4bfea7c95
2023-11-05 03:37:33 +00:00
stephan 88c90a793e Add authorizer support to JNI wrapper1.
FossilOrigin-Name: 773f9873865b5277a6a682c4695f216bfe1ec05ed5e5a2a70aaa451934ba2dc0
2023-11-05 01:55:20 +00:00
stephan 9a26589940 Add progress-handler support to JNI wrapper1. Correct the return type of the extended_result_codes() JNI binding and expose it to wrapper1.
FossilOrigin-Name: 6c0acfdce2160d8db261a59677cec571b6abc333481525b1ec975d98e88bec88
2023-11-05 01:39:29 +00:00
larrybr 557297ae77 Setup, takedown, mode set and output working. No input yet. (WIP)
FossilOrigin-Name: dfea85be1fb927ea446c9d98bae42ba1197bdab098aa6d95aa512a37d07a1e52
2023-11-05 01:21:14 +00:00
stephan 0ee7ae72a1 Add update-hook support to JNI wrapper1.
FossilOrigin-Name: 6c584cf27179d16deee84e9699493cf29bebef123fa2a7493aad0324bead1618
2023-11-05 01:14:07 +00:00
stephan 2c930e3b86 Add commit/rollback hook support to JNI wrapper1.
FossilOrigin-Name: ff3d44fe42528d96533d22c7807472df89bca18f1def23b018e2f407318143f8
2023-11-05 00:48:43 +00:00
stephan b02ca781ad Add busy-handler support to JNI wrapper1.
FossilOrigin-Name: dcf579ab2de4a3d3a437cde59b2fd60f1729c0bde31df1865117e6a5ea4bab20
2023-11-05 00:02:47 +00:00
stephan 15d38c0dde Bind collation and collation-needed to JNI wrapper1 and correct the callback return type for collation-needed callbacks in the lower-level JNI binding.
FossilOrigin-Name: 0f673140681685ab390ecd7326a8b80d060b7ab23c31a2cfc28ba76fd5096afe
2023-11-04 23:37:11 +00:00
stephan dc8a684c11 Wrap the sqlite3_backup API in the JNI wrapper1 API.
FossilOrigin-Name: 3ee6cc29d2111e7ad90860827c0ea808fdf07bc71defdade7e6794ec4a2a3ce2
2023-11-04 22:47:40 +00:00
stephan ffdb479e7c Reimplement auto-extensions in Java for use with the JNI wrapper1 API.
FossilOrigin-Name: 14ed4c64533622e5faf1aaa59c24885885aad43f1c0d4717773e79440e8e1468
2023-11-04 21:51:34 +00:00
drh d4677f192f Ensure that the YYYY-MM-DD input to date and time functions has been normalized
prior to returning a result.
[forum:/forumpost/6bb476897e|Forum post 6bb476897e].

FossilOrigin-Name: b692eb8ccb2d0645599ad73a8bdacf5df499114244aadeb38aabc580fc4dc7c5
2023-11-04 21:44:00 +00:00
stephan 1b199243cb Expose context_db_handle() to the JNI wrapper1 API and clean up some related tests.
FossilOrigin-Name: c23123af7d40dea24a0848dff987fd58a6703ce04165060533544db85983d566
2023-11-04 16:01:13 +00:00
stephan 348e192ea8 Rework the JNI wrapper1 variants of status() and db_status() to be more Java-esque.
FossilOrigin-Name: 40ad3920673561a06edf0b70a50a40be6cd20817fe22b87b63a9ac80cb2c9df8
2023-11-04 13:37:42 +00:00
stephan 5f3b13d136 Bind the bool-flag sqlite3_db_config() variants to the JNI wrapper1 API.
FossilOrigin-Name: b5cdcb9279d9276f24b67083839f463beecd731f46f2e8bf68fff716df0a3921
2023-11-04 13:16:49 +00:00
stephan aad6808efc Bind the trace API to the JNI wrapper1 API and add a way to map the native-level db/stmt types to their high-level counterparts (required for translating callbacks such as tracers).
FossilOrigin-Name: 702910e0d1cfc897a269b4fb36b255165958edf529ac9553ebc5155e404d4cd3
2023-11-04 12:53:00 +00:00
larrybr a501791d59 Define interface between project command-line apps and a console I/O "library".
FossilOrigin-Name: 64abef8314b8544fdc7b71317d61a4641dc607a1ae42b8ff21543226fd338ba2
2023-11-04 02:22:04 +00:00
drh 5189ef98d3 Back out the ALWAYS inserted late yesterday. The fuzzer discovered a
counter-example.

FossilOrigin-Name: 570635575cc5fbffe910ed992b58393e214117ef3b5370a66f115cd0ee202913
2023-11-03 18:45:26 +00:00
dan ab8a4b2bb0 Fix a case where adjacent tokens are handled incorrectly by the fts5 snippet() function.
FossilOrigin-Name: 8f5e9c192ff2820d8cfb076ab28f30697d10c22710583d6c7fd7019c4a0ea795
2023-11-03 17:20:20 +00:00
stephan b945183195 Wrap more of the stmt API behind the JNI wrapper1 API.
FossilOrigin-Name: 8fea23dc3af023ccf2909f1b4c6f91e7df0ffaac875b15f1fb3e264fba169b6a
2023-11-03 13:00:51 +00:00
drh 7b5123c796 Enhance the JSONB lookup routine with logic to apply edits. The new logic is
currently unused and hence untested but does not create any regressions.

FossilOrigin-Name: b12110276fc15d1b6b0cc455f89747ace7a09650d5ba433d8bb431bb4e5bc951
2023-11-03 12:09:22 +00:00
stephan 073f8f5458 Bind the sqlite3_keyword_...() and sqlite3_compileoption_...() family of functions to the JNI wrapper1 API.
FossilOrigin-Name: b27242414d6023eac7e62cf6120e1f02b0ddc7b8f0a1e4c48111cfe88d197cbd
2023-11-03 11:53:13 +00:00
drh 1d5f2af063 Update the tool/srctree-check.tcl script so that it verifies that autoconf
has been run following edits to VERSION.

FossilOrigin-Name: 52ab3deba4d26ca0e9a84a6dff254195b4a0e2cc6cf948cf7a66bb11117e7002
2023-11-03 11:41:24 +00:00
drh 24f7f5923d Merge all the latest trunk fixes and enhancements into the jsonb branch.
FossilOrigin-Name: b089bf46374b374d02d7654c65eb3e75d1777638b398061e47644af0dab48c9b
2023-11-03 11:35:33 +00:00
drh d706adba48 Update the version number to 3.45.0 to begin the next development cycle.
FossilOrigin-Name: 15b618e92a2708cc83256947736de8c494a9985a77e38bd5efc7e51e72cba344
2023-11-03 10:15:16 +00:00
drh dcd6d21fe9 Mark a branch made always-true by the penultimate check-in with ALWAYS().
FossilOrigin-Name: 268b5984a4263bee245a9bb47ac927bde56cdf4af8795b851dada5622224076f
2023-11-02 22:39:11 +00:00
drh 792103a0f2 In the previous check-in, use a u32 instead of an int, to make it easier to
prove that the integer will never overflow.

FossilOrigin-Name: 51002079e0b499e116415189a913a238e95ed9766a8af9d042928f4263861a87
2023-11-02 22:11:35 +00:00
dan 5e4233a9e4 Fix a spurious "misuse of aggregate function" error that could occur when an aggregate function was used within the FROM clause of a sub-select of the select that owns the aggregate. e.g. "SELECT (SELECT x FROM (SELECT sum(t1.a) AS x)) FROM t1". [forum:/forumpost/c9970a37ed | Forum post c9970a37ed].
FossilOrigin-Name: 4470f657d2069972d02a00983252dec1f814d90c0d8d0906e320e955111e8c11
2023-11-02 21:02:53 +00:00
dan 78fee3f738 Add the "remove_diacritics" option to the fts5 trigram tokenizer.
FossilOrigin-Name: 0d50172477064dce3f7c61641d88aa15d8a1edea9872adaffcc1a7a1c9ab0e93
2023-11-02 18:22:35 +00:00
dan 7b0fd0c564 Fix a problem with amalgamation builds on this branch.
FossilOrigin-Name: 8f046c82c9cf51fc349674577c68d3d2499ee37009deacbf937d711d9930fd49
2023-11-02 18:10:22 +00:00
stephan 06af40b2e1 Merge latest JNI pieces into trunk.
FossilOrigin-Name: e8c97faec339430fa2d1a7e915050d9b363bdba606a4419397cb099141da254d
2023-11-02 18:08:49 +00:00
dan e186fe20f5 Add the "remove_diacritics" option to the fts5 trigram tokenizer.
FossilOrigin-Name: 83da80135b6105f47d1de560232449562ae8ac176c8011a6f75589f62bc9b1db
2023-11-02 17:31:06 +00:00
drh 845a2e0cc2 One more tweak to tool/srctree-check.tcl so that a complete build can be
accomplished from a read-only source tree.

FossilOrigin-Name: cba9f0601ca995ac6952aa3a83f7264f6d25aaaa2ea36b19e90cbf591077de72
2023-11-02 13:10:16 +00:00
drh 8a93ce7458 Update the srctree-check.tcl script and child script so that they can be run
on a read-only source tree and so that if any inconsistencies are found, the
script returns a non-zero exit code and thus halts the build.

FossilOrigin-Name: 58eb5440d75fb13c1a089cb935de6fb94b4322e10e349db8f11f37b9a2fda2fc
2023-11-02 12:05:55 +00:00
larrybr 57a7fdd814 CLI to compile with older MSVC compiler.
FossilOrigin-Name: c89f75f8eef449f6869bda423593f7e14080e805f8ed192aff9463460f11b1a9
2023-11-02 11:04:37 +00:00
stephan 7d52262889 Remove some outdated JNI docs.
FossilOrigin-Name: 52aef3d015bad12c4bd9334ec795276a68a0dabdc6fd0ff2a1068f640171eb77
2023-11-01 20:09:02 +00:00
drh 0577cdec5f Update the windows build documentation to provide the exact command used
to build the DLLs that appear on the download page.

FossilOrigin-Name: 3524a8914c62f7987d948e5ef50cfdcb07254489e80e2257f38d0050c4baf450
2023-11-01 19:35:15 +00:00
dan 54e7a0f360 Fix testrunner.tcl so that it accepts a relative path as an argument to the --zipvfs switch.
FossilOrigin-Name: c1ed7ed02269e5b26142eb307e7889fc636672f101ea7fc192a2445e16a7dd6f
2023-11-01 14:33:44 +00:00
drh 2158864585 Bring the jsonb branch up-to-date with version 3.44.0 changes.
FossilOrigin-Name: a420a4f7ff76b0e9cf5f6d515ccfa31e526d58f4001a4015a367e2aa3c82091f
2023-11-01 14:12:07 +00:00
stephan 793e872803 Merge trunk into jni-post-3.44 branch.
FossilOrigin-Name: 9670eb2496b4005cf718d9fd12dbd11733f7cf6704a967ebb316504ea6a51e82
2023-10-28 03:56:14 +00:00
stephan 95c11b1158 Add missing docs for the JS Worker1 export method, as pointed out in [forum:75524f7342|forum post 75524f7342].
FossilOrigin-Name: a7b267bd11216ee990cdd855044fbc18c300dff07cf25b317f27c1bbbc340dcc
2023-10-27 23:02:01 +00:00
stephan 26422f823f Export sqlite3_get_autocommit() to WASM and add tests for it.
FossilOrigin-Name: 7cb6d3cd3926882240c91a4b90fdf237b931653295d8d94b05ed885dcae59608
2023-10-27 21:05:50 +00:00
stephan 334b6fe418 Add missing JNI sqlite3_result_subtype() binding.
FossilOrigin-Name: ac920b5386db525c794f4cae332dedcc709cac356f6fb85f3e92bc0a34602511
2023-10-23 02:06:27 +00:00
stephan 90a5617b55 Add many more high-level wrappers to the JNI wrapper1 API. Correct the JNI bindings of sqlite3_strglob/strlike() to compare as the core lib does if their glob argument is NULL and the other is not.
FossilOrigin-Name: 55c4b1dc402b358d53d65fa1f6ec063e9e38e95c81a05d98dae3cb58c52ef55c
2023-10-23 01:34:17 +00:00
stephan 96aa4d344d Add high-level window function wrapper to the JNI wrapper1 interface.
FossilOrigin-Name: a27e7471231a24864cbd04b77cbc4b336ce180d738a36ce4318543e2666ed708
2023-10-22 23:36:16 +00:00
stephan 166c8d0067 JNI: flesh out and simplify the APIs for binding and fetching arbitrary Java objects.
FossilOrigin-Name: 89fecf1dd8b97941f9b45130a3c8a67af36ec65cc6f70f5026c569c058a4963f
2023-10-22 14:25:37 +00:00
stephan 32a0d6129f JNI: add column-get bindings to the wrapper1 Stmt class and extend the AggregateFunction tests to ensure that the aggregate context is honored.
FossilOrigin-Name: 60a0e82db26270af9d0a5f55c6173e4fd0bdc90a885e838480ed75f8ef193287
2023-10-22 13:54:26 +00:00
stephan 4598b6e5ae Add API_ARMOR to sqlite3_clear_bindings().
FossilOrigin-Name: f3fb4d345bbf5ae4a35d8076043df601b1bf7dfd68760a416440139eb3e5eb9a
2023-10-22 13:09:37 +00:00
stephan 4bcde614d8 Add JNI wrapper1.SqliteStmt.bindXyz() APIs.
FossilOrigin-Name: 54fce9bf04a7517cdc8e96fe2efec66f03b0d03983c3a45d0ae7e1f16aa5a6c9
2023-10-22 12:43:30 +00:00
drh f5e487d168 Merge recent trunk enhancements into the jsonb branch.
FossilOrigin-Name: f47a8d0a207a8442a7f621b070ce9dd1d6013ce26bcf68165d20bb379bd478a0
2023-10-19 20:46:22 +00:00
drh c7ad9f65fa Merge fixes from trunk into the jsonb branch.
FossilOrigin-Name: a760bd7bcc63aac41c989bb5f4fbc927f9a93fe9c0aa18da2f0131483ec3f189
2023-10-12 17:47:50 +00:00
drh 7d1c9da62d Fix the use of an uninitialized value that occurs when doing a json_insert()
of a string value that contains embedded U+0000 characters.

FossilOrigin-Name: fc5ee9e51ad4556af526a6cefca5ae5a3b1b7affc4edf09832491d6b4f4ba366
2023-10-11 17:21:16 +00:00
drh 86db4555ca Fix a missing zero-terminator on a string when processing
JSON aggregates into JSONB.

FossilOrigin-Name: fb81d570a3d9b8f55e9f278d5240605c5d0f3c5abde51550797999d03cf193a7
2023-10-11 13:19:37 +00:00
drh 2b7a1f5926 Fix an issue that can arise when processing corrupt JSONB.
FossilOrigin-Name: e50045c22296be84c6bea82bb8b310f07bca820c84d4a7349b16da0cf5d2657c
2023-10-11 12:44:17 +00:00
drh 33b56217cb Improved robustness against corrupt JSONB.
FossilOrigin-Name: 0fbda92bb0eeb40f95c83f717e4e8f5bff1ac82f1c899e9f6d400d67df67214e
2023-10-11 12:21:29 +00:00
drh 2a96a1584d Fix an assertion fault in json_patch() that can occur if the patch JSON
is malformed JSONB.  Report the malformed JSONB instead.

FossilOrigin-Name: a72d54645ca0dd80c60a5ed586049dead3ea7f5fa9ad05c6610a506242a7032a
2023-10-11 11:42:06 +00:00
drh 71dc3c714b Improved robustness in the decoding of JSON5 text escape sequences found
in malformed JSONB.

FossilOrigin-Name: 35e0108af2bdd830375c31c525f8ed0e8df64959d89649a88402dc1a5c376612
2023-10-10 23:02:31 +00:00
drh 6b7b23c580 Fix an off-by-one error in the changes from the previous check-in on
the jsonb branch.

FossilOrigin-Name: 216191b113da43516d31301fb133173add66358d503677ab997bc82cc88bfea4
2023-10-10 18:55:29 +00:00
drh 59ded6b5f1 Improved robustness when translating corrupt JSONB into JSON text.
FossilOrigin-Name: 0caa320d9099adbaf98e3719003dbdc4d158abcb3d8a1af20fbcd4c08c970f4a
2023-10-10 18:42:08 +00:00
drh d88f378c7d Fix a potential buffer overrun due to corrupt JSONB.
FossilOrigin-Name: 5cbb861fc6cb7421a81c957ba9d576e0ae92cb4ed725cdb539b364d66f4ee145
2023-10-10 18:32:14 +00:00
drh 064c1688da Fix bugs uncovered by the fuzzer.
FossilOrigin-Name: c96eb7fb618dc0a5aeec8a5e85076475b77dcd56309438aba1f9bddfc8921e3c
2023-10-10 18:04:40 +00:00
drh cc5e612db4 Merge the latest trunk enhancements into the jsonb branch.
FossilOrigin-Name: f93f16c94d0a58dfa90939e84aba048be958c7b085b45a6f25c2243fdf79b3aa
2023-10-10 17:34:41 +00:00
drh f32aa34346 Systematize the names of some of the translation function in the JSON
implementation.

FossilOrigin-Name: db44bd1d62084ef69c808f7d07e0a25d5a089dcb8b98b1b5d026777591bbdefc
2023-10-09 18:33:01 +00:00
drh 0dead8d3d1 Merge the latest trunk fixes and enhancements into the jsonb branch, and
especially the JSON cache spill UAF fix.

FossilOrigin-Name: 9422c24f4a8b290dcae61e50ec81be5b314b22c61a2bca1e194e47da1316b6e6
2023-10-09 12:57:03 +00:00
drh a7e9386e88 Remove some unnecessary code. Report errors for invalid JSONB input on
an extract.

FossilOrigin-Name: cbea16c29eb0507f39b5a1cf744a3bb9bb7c71ac156e84a19d03a37cb1816891
2023-10-07 23:35:07 +00:00
drh de8ccf00fb The return from sqlite3_value_blob() in jsonFuncArgMightBeBinary() might
be a NULL pointer.  Check for that case.

FossilOrigin-Name: 7b52b266b066f1385144c1103a3a411306db5f44568366ae1e93cd8cce799bbc
2023-10-07 19:46:22 +00:00
drh 3efb2c4791 Improved detection of malformed JSONB when parsing it into a JsonNode array.
FossilOrigin-Name: ed99a788415e1f8375bd5ec004dd18b1cd0fae4aa94558170882ca487f6dff93
2023-10-07 19:40:20 +00:00
drh f26833d783 Fix the jsonbChangePayloadSize() routine so that it shifts the payload in order
to always render the most compact encoding of the payload size.  This is
necessary as sometimes (as discovered by dbsqlfuzz) the payload size can
grow significantly due to json_insert() or json_replace().

FossilOrigin-Name: 8d6d04ca975ec55c419d40d8463c433b0db698c9fb4812ab9f16d4ee5bee460e
2023-10-07 19:05:10 +00:00
drh 1244b6cbf6 Improvements to error messages returned when the ->> operator fails.
FossilOrigin-Name: 2f3388f14c843f1c02926e8b929365c06c1f1f4ea6fe6316092c3799c14549d3
2023-10-07 17:50:06 +00:00
drh 502b11c6d3 Merge the memory leak fix from trunk.
FossilOrigin-Name: 358de1b09f3d5ec0fe459775b0a2a99dfa235817327016b472aaa1ed56d952e6
2023-10-07 11:37:00 +00:00
drh bae197c175 Improved error messages from search on JSONB.
FossilOrigin-Name: 96cfdc31e305406123f6ef1b920423f71902dc4b34381c3efb720274343d37cc
2023-10-07 11:36:16 +00:00
drh 522e880bc2 Report unknown JSONB element type when parsing JSONB into JsonNode.
FossilOrigin-Name: 1f4d3268257bda234c66c3767451b3d39d7b4c7c73a779ad396d9dfc5315905c
2023-10-07 09:13:59 +00:00
drh 11aa2adca3 Correct handling of "raw" strings in JSON. This requires three test-case
changes in TH3 to add double-quotes to the path outputs from json_tree().
The new behavior is correct, I believe.

FossilOrigin-Name: ab2bf3e3596dfa7566f4a130adeccbef4056c7321181112a875477193583f30c
2023-10-06 23:02:06 +00:00
drh 6b8aa95c3c Improved error detection for JSONB inputs.
FossilOrigin-Name: 6945e11aa441ace52b93cdbb81ac45b6f809987f3dbc522251e63f8cb948fddd
2023-10-06 22:16:09 +00:00
drh 7b4349735f Incremental improvements to the JSONB logic.
FossilOrigin-Name: fe326829c27715e249f727ba797c7df6491e874ec205a0a82ee09c78d61c6e1f
2023-10-06 18:21:47 +00:00
drh 98dbfa69d3 Fixes to rendering JSON5 extensions encoded as JSONB.
FossilOrigin-Name: 5a17e4479aad2d8313170e5de83a1c52f30b55d9d4fb776024fa6622e175c63b
2023-10-06 15:35:42 +00:00
drh e690d5ad80 Fix compiler warnings.
FossilOrigin-Name: 5227add3c8d509de2e081249163fafdf30ac3173a6d710957f3c3b6f03e7017e
2023-10-06 14:59:40 +00:00
drh e1e2f2dcc5 Improvements to error handling.
FossilOrigin-Name: b41dd237fb6c0dd7daedeaaf81dbc4fdb31cf511fd32cd3d4ee69db34e389915
2023-10-06 14:52:49 +00:00
drh 91f3cd9874 Merge compiler warning fixes from trunk into the jsonb branch.
FossilOrigin-Name: 6409d307915f8969f12df2d5ffa961645bd4db7ccfbd6f52237a217b6a867252
2023-10-06 13:05:42 +00:00
drh dd7f09e6c0 Improvements to coping with malformed JSONB.
FossilOrigin-Name: 563cde404cec4c6559ae0c5fc5edbc878fee874b36562ce2fac5049cc8349343
2023-10-06 00:06:26 +00:00
drh 27401d38d8 Better error detection when doing a lookup on a JSONB.
FossilOrigin-Name: 6e8e0eedbf06e175af6ef230f1ce9a5ad84698b1c6dcd2794d878c746e7b6be4
2023-10-05 23:05:35 +00:00
drh f7af8f3270 Improvements to comments. No changes to code.
FossilOrigin-Name: ac74d7877685006e43684edd6a2d22be8c9857f9f9eb52fc5b3c182d5e2fdb8d
2023-10-05 22:52:43 +00:00
drh dac2707152 Turn an unreachable branch into an assert().
FossilOrigin-Name: 0f75199160e48fa8c44f986f1af777adf19e40fbd114a6f58e24d5e6dede779d
2023-10-05 20:17:01 +00:00
drh 51d507d432 Fix the parsing of non-standard "Infinity" and "NaN" values from text into
JSONB.

FossilOrigin-Name: df1fbbeb83a2b4a496c9de0d86c7c8c677f8fe3bc770da163dcc1d338a17b58b
2023-10-05 18:33:19 +00:00
drh 5b6cfb7906 Change the json_valid(X) routine to return true whenever X is a blob that
could plausibly be a valid JSONB.

FossilOrigin-Name: 425f0b85a6f8ad0604c4a5faa18efb90436fedb1fe2612a559147c62cff8b7e7
2023-10-05 18:09:12 +00:00
drh 14fce24a9b Fix the text-to-JSONB parser so that it handles some JSON5 floating point
literals correctly.

FossilOrigin-Name: 564edb3b6dd752e09e445e3a25c2f5394ceede2a2cdff251d6433dadc0b3644f
2023-10-05 17:52:39 +00:00
drh 0585d9f08f Slightly stricter testing for when a BLOB is valid JSONB: If the element
is a null, true, or false, its payload size must be zero.

FossilOrigin-Name: 487781be8a93d9b8d870efb9f25822bb4bbcf9d39d571d1017e9c29043ea515d
2023-10-05 16:33:00 +00:00
drh 01acfd5805 Fix a memory leak following a syntax error in jsonb().
FossilOrigin-Name: bf4b36eda8e200b67041ebdf60fc31d0325bd84185272f8d390c56a91d6ac1ee
2023-10-05 15:05:33 +00:00
drh 9061e22a05 Allow the PG-style syntax for the PATH operand on the right-hand side of
the ->> and -> operators.

FossilOrigin-Name: bae5071b0834aa3b7fd4bd871f863e1b148c6558989c8f6cdd02dc4da4770953
2023-10-05 15:02:00 +00:00
drh 0f921e2bac Merge trunk enhancements into the jsonb branch.
FossilOrigin-Name: be5907b648386e05530d1e321e2a3e563e07e99f08373aaf9a3452adc9228dc3
2023-10-05 11:22:16 +00:00
drh 4500d87e76 Fix a memory leak in JSON group-aggregates when the output is JSONB.
FossilOrigin-Name: 08e7db138b636890cb29a76d65c2069c6e2ff44470fa4bca14f4526fe5f195ae
2023-10-03 22:40:22 +00:00
drh f362731c1c Fix a bug in the jsonReturnFromBlob() function that causes a positive result
for a negative value for when a JSON integer is too large and needs to be
converted into double.

FossilOrigin-Name: dca684da0c29ec78460362f972ea7747be42c13c4d1325da9d62c1ea58022e39
2023-10-03 21:54:09 +00:00
drh 51cc3041fe Fix problems in the "json" output column of the json_tree() virtual table
for the case when the input is JSONB.

FossilOrigin-Name: fefa4475c496aab32fe7b9cc203747ce4faf7448da4f29b807e5486c7686238d
2023-10-03 20:58:39 +00:00
drh 6e737b9252 Improved handling of OOM while translating the JsonNode representing into
the BLOB representation.

FossilOrigin-Name: ef5956710bb542d6045c82937d02218a7ed45af94cf3959b0c180268e04d14e1
2023-10-03 19:37:19 +00:00
drh f0c129f247 Merge the latest trunk enhancements into the jsonb branch.
FossilOrigin-Name: e6406a9865b75dea2f26d3ee4f4c206958400059c7f92ced88edc8507dd3c82f
2023-10-03 11:36:47 +00:00
drh ee0f6777f9 Fix a problem in the JSONB parser that comes up following an OOM.
FossilOrigin-Name: 355acfb18897254f6b6444a21d781b5e10e930b81952850dd2a40d88bbf2f3db
2023-10-03 10:59:01 +00:00
drh 8405e1140a Fix an issue with the use of jsonb_group_array() and jsonb_group_object()
when used by window functions.

FossilOrigin-Name: 808bd349ba587fbcdc4aea3f9c08e0df01ba08dec181c5af5ea157e89d86ff7b
2023-10-03 10:43:30 +00:00
drh 313336f90b New test cases for JSONB.
FossilOrigin-Name: 6d4aeff5751722c83ebb0e1f21072b72be418c64dcf28ee032d3a548e1b3a951
2023-10-02 23:56:46 +00:00
drh e5c384e9a5 Fix jsonb_insert() so that it does not behave like jsonb_set().
New test cases added.

FossilOrigin-Name: 54197149b811d30b6c4487eedf5692b164ed0f90cfcc541aa3157094f5f17f6a
2023-10-02 20:16:06 +00:00
drh dee29e8c7a New test cases for JSONB.
FossilOrigin-Name: d624c31e5c49e1ce63b4b72caa42a61c5167866f47d842fbcfe4e826fd079d7c
2023-10-02 14:51:28 +00:00
drh c97407fdba Allow json_replace() to accept JSONB arguments as the new value.
FossilOrigin-Name: 95eb7b37fab29931924311f541d52173ef77a448efc8771b1a1783ccd786d23d
2023-10-02 13:35:06 +00:00
drh 8eeafb7544 Improvements to error handling for BLOB inputs on JSON.
FossilOrigin-Name: 14f20ecbfab44934e86f1ac7a3f745b989aa8190c6df119ff5aa8100fa248d93
2023-10-02 13:20:43 +00:00
drh 5624b0b4cd Gather forward references into a single place for the JSON code. Allow
JSONB arguments to json_array() and json_object() and similar.

FossilOrigin-Name: c352201b8c299c330d9abbff6dbcbcbcf00ada53183d3cd91020ec772e066357
2023-10-02 12:40:04 +00:00
drh 9b176f863b Fix problems following OOM in JSONB parsing.
FossilOrigin-Name: 0d8cd6b5fb592f88f593ceaad9cdfa95dcfdf14169c3a56a5becbd66d62fd02b
2023-10-01 18:59:34 +00:00
drh d8f26350a0 Restore the trunk version of sqlite3_user_data(). Fix the xColumn for virtual
tables so that the sqlite3_context contains a valid but NULL user data pointer.

FossilOrigin-Name: 15ffd932fecc82a5791b2024f55d2ec80887e8eb7345de68d6f5cac4912cfbe8
2023-09-30 16:50:17 +00:00
drh 7e86d3fc69 Finish adding jsonb_ versions for all JSON routines that return JSON text.
FossilOrigin-Name: 6daa7b69695e1b68dba317abbcad4d0205c91963d4a9eb2d595a3ec10fa0fdf4
2023-09-30 14:34:39 +00:00
drh 5736ba5ac3 Update json_each() and json_tree() so that they work with JSONB inputs.
FossilOrigin-Name: bb5e50ff56dff95d954aacdd4c5461790f953cef8d7b89da000d8d587fcdf9b8
2023-09-29 22:37:18 +00:00
drh ee50aad865 The u.zJContent field of JsonNode for a string or label should NOT include
the quotation mark delimiters.  Ever.  This is an inefficiency that really
ought to be fixed on trunk, but that can wait until this branch lands.

FossilOrigin-Name: 96f545f6f839dab4829861361ee3d7a56840217c5f954f334616e77d23c5fe29
2023-09-29 19:47:25 +00:00
drh a99e2fb576 Additional refactoring and cleanup.
FossilOrigin-Name: 45dd1760875b1ad899a10189c6f5a0a9a0677903794fb5a06ffacd39952a7882
2023-09-29 16:37:22 +00:00
drh ae5f55e227 Improvements to comments and procedure names for clarity in the JSON
implementation.

FossilOrigin-Name: 9b620d813ef483f1277c1683c5e926a882f07f3b90804dea0c91b325ff8e45a4
2023-09-29 12:45:14 +00:00
drh ecce6022d5 Describe the JSONB encoding in a header comment to the json.c source file.
FossilOrigin-Name: 1c0cba3461d6111b3aeb77726880221f1240355f0b57e060febbdeb12fb688c0
2023-09-29 11:17:43 +00:00
drh 8cdab14286 Fix some minor memory issues so that all legacy tests now pass.
FossilOrigin-Name: 1744bfc669346ff221f28d45fd978863e876a2d2f0b82bcf0e5ee6f0326900cc
2023-09-28 19:11:36 +00:00
drh 0a19bb078d Allow the sqlite3_user_data() function to be invoked with a NULL argument
or with an sqlite3_context pointer from a virtual table.  It returns NULL
in both cases.

FossilOrigin-Name: 2f49687371ada65fef374336c28b352c48ab98dc31282ac82397035efe04ba11
2023-09-28 18:23:52 +00:00
drh edbc44c5a1 Merge trunk changes into the jsonb branch for the compiler warning fixes
from two days ago.

FossilOrigin-Name: cee113cc315b04fd75ccc172cf4529bf15b2050bf274433496c31a282e281ab8
2023-09-28 17:41:45 +00:00
drh 77e00f24d7 The json_extract() function now works on BLOBs without the need to translate
into an array of JsonNode objects.  This is much faster.

FossilOrigin-Name: 5853065b7ee326c04ddfcde64c178f487af04cd3adc3cc99f559907484ec169d
2023-09-28 17:27:24 +00:00
drh 6b1db92228 Extract directly from BLOB is now complete and appears to work.
FossilOrigin-Name: 3de58ec99444b16dfcda1e226420e2343450b77abd3faf33a88b6d18339ef17c
2023-09-28 17:23:46 +00:00
drh 59862e6d22 Miscellaneous bugs fixed.
FossilOrigin-Name: 5c0815fa2e422d81198a43a2c04a022e319fcbcadfd4be4437f2e663892ca26b
2023-09-28 17:07:43 +00:00
drh 2dc60ec57f Improvements to json_extract() to better support JSONB. Still not 100% working.
FossilOrigin-Name: 8c82576176539c4d132b14d46adbf31366c4bcaa59a61dd639dc9cc308fe8825
2023-09-28 15:56:35 +00:00
drh 1854837b5a Work toward getting json_extract() to operate directly on the BLOB, omitting
the translation into a JsonNode array.

FossilOrigin-Name: c1feba70f55a8e5f4696d48e4706855415d173ac8ac3c2656787c242a883b4f5
2023-09-28 10:20:56 +00:00
drh 733da8d31a Performance tests for JSONB added.
FossilOrigin-Name: 7c1be8e361db87458ac9d8fcee080c2b558936539c852bb80f0f7941d61bf15d
2023-09-27 16:55:13 +00:00
drh 676bcf7457 Merge partial-index constant value fixes from trunk into the jsonb branch.
FossilOrigin-Name: 700bdbd7383f66a0da675c197204da4e7b6ed757155145ee98d572de32a5d0ae
2023-09-26 19:46:38 +00:00
drh 42156fd90c Add in many jsonb_xxxx() interfaces. Still uses the internal JsonNode
representation for transformations and search, but it does at least conform
to the desired API design.  Largely untested.

FossilOrigin-Name: e6045b4e1bf3a8e33926fc12b3c039f5e1002eaecbe277ffa82b0ec271a29d17
2023-09-26 19:30:46 +00:00
drh 219e7f7986 Merge all the latest trunk enhancements into jsonb branch.
FossilOrigin-Name: ac242c4d47ec36aab1c2fa5e65e7b595e686f49473b75bd63708d05c59ce3f0f
2023-09-26 15:13:04 +00:00
drh 09f23d2a36 When parsing JSON text into the BLOB format, only use node type JSONB_TEXTJ
for an unquoted object label if the object label contains escape sequences.

FossilOrigin-Name: a82ebbac3c542ec7f86d1e8414d7fd166db48450115ee3b26d12b5bb445f5896
2023-09-25 17:14:17 +00:00
drh 5933581cf0 As a temporary measure, try to translate the BLOB JSON format into the
legacy node format for processing.

FossilOrigin-Name: 14f2e95a9e531ef0d3fa7f1249f23c073a50c31b2109eefc2f258cada635ac2f
2023-09-25 13:23:29 +00:00
drh e367e453e1 Fix minor parse-to-BLOB bugs.
FossilOrigin-Name: 8b53b2e6600c324ff7864840d98a3f03896b9792fcb60b70cc1f6227b3bd4ca1
2023-09-22 16:20:48 +00:00
drh c1c1d4d4a6 Add the ability to render a binary BLOB back into valid canonical JSON.
FossilOrigin-Name: 0b70cb77a4c8e3f17932f1ecca3942e0b0b03de637fb9656a130fe045f7ef826
2023-09-22 14:33:39 +00:00
drh 90189be7ce Begin adding code to render binary JSON back into text. Very incomplete.
This is an incremental check-in.

FossilOrigin-Name: b817dd865ed60fc4da0b662a9edec0fceb8921b02ce98133bdd565988939fd0f
2023-09-22 12:16:56 +00:00
drh 8c55945220 Improvements to the JSON binary BLOB format design.
FossilOrigin-Name: 2c89ae5d02f6a40ef869e2a162e2c72871df60572b27959fd1d7171f495ce881
2023-09-22 11:20:35 +00:00
drh 769a8dea81 Reorganize the code to put the new JSONB routines together, for easier editing.
FossilOrigin-Name: dc23e783d4147d363856abe109586fc79a5b535b492beee0cf7a0234c0210667
2023-09-21 18:16:35 +00:00
drh 6831cad03b Initial development code for an experimental binary BLOB encoding for JSON.
FossilOrigin-Name: 8131b3c272f47db2618886046a9713285ce120cb87d721484ee7444273290681
2023-09-21 17:51:39 +00:00
dan 4ffaa7c5de Passive checkpoints do not use the busy-handler. So, in order to minimize visible changes for legacy applications, do not enable blocking locks for passive checkpoints.
FossilOrigin-Name: 9c2b4bdd03716bf492ba85198717f3084ebf187bdb068893bd1ff8662362df89
2020-06-29 19:58:26 +00:00
dan 5289c51050 Change things so that if SQLITE_ENABLE_SETLK_TIMEOUT is defined as 2 instead of 1, all blocking locks are taken for a single millisecond and the default busy-handler invoked as normal.
FossilOrigin-Name: ac381e6eb3c9284e65f7aad66d21bee1bca9ef4123684ccaf069b8a6d157a56d
2020-06-29 18:22:21 +00:00
89 changed files with 9266 additions and 6025 deletions
+27 -12
View File
@@ -710,6 +710,21 @@ fuzzcheck-asan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
fuzzcheck-ubsan$(TEXE): $(FUZZCHECK_SRC) sqlite3.c sqlite3.h $(FUZZCHECK_DEP)
$(LTLINK) -o $@ -fsanitize=undefined $(FUZZCHECK_OPT) $(FUZZCHECK_SRC) sqlite3.c $(TLIBS)
# Usage: FUZZDB=filename make run-fuzzcheck
#
# Where filename is a fuzzcheck database, this target builds and runs
# fuzzcheck, fuzzcheck-asan, and fuzzcheck-ubsan on that database.
#
# FUZZDB can be a glob pattern of two or more databases. Example:
#
# FUZZDB=test/fuzzdata*.db make run-fuzzcheck
#
run-fuzzcheck: fuzzcheck$(TEXE) fuzzcheck-asan$(TEXE) fuzzcheck-ubsan$(TEXE)
@if test "$(FUZZDB)" = ""; then echo 'ERROR: No FUZZDB specified. Rerun with FUZZDB=filename'; exit 1; fi
./fuzzcheck$(TEXE) --spinner $(FUZZDB)
./fuzzcheck-asan$(TEXE) --spinner $(FUZZDB)
./fuzzcheck-ubsan$(TEXE) --spinner $(FUZZDB)
ossshell$(TEXE): $(TOP)/test/ossfuzz.c $(TOP)/test/ossshell.c sqlite3.c sqlite3.h
$(LTLINK) -o $@ $(FUZZCHECK_OPT) $(TOP)/test/ossshell.c \
$(TOP)/test/ossfuzz.c sqlite3.c $(TLIBS)
@@ -1135,21 +1150,21 @@ keywordhash.h: $(TOP)/tool/mkkeywordhash.c
# Source files that go into making shell.c
SHELL_SRC = \
$(TOP)/src/shell.c.in \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/consio/console_io.c \
$(TOP)/ext/consio/console_io.h \
$(TOP)/ext/misc/appendvfs.c \
$(TOP)/ext/misc/completion.c \
$(TOP)/ext/consio/console_io.c \
$(TOP)/ext/consio/console_io.h \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/basexx.c \
$(TOP)/ext/misc/base64.c \
$(TOP)/ext/misc/base85.c \
$(TOP)/ext/misc/decimal.c \
$(TOP)/ext/misc/basexx.c \
$(TOP)/ext/misc/base64.c \
$(TOP)/ext/misc/base85.c \
$(TOP)/ext/misc/fileio.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/ieee754.c \
$(TOP)/ext/misc/regexp.c \
$(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/shathree.c \
$(TOP)/ext/misc/sqlar.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/misc/uint.c \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/sqlite3expert.h \
$(TOP)/ext/misc/zipfile.c \
@@ -1158,7 +1173,7 @@ SHELL_SRC = \
$(TOP)/ext/recover/dbdata.c \
$(TOP)/ext/recover/sqlite3recover.c \
$(TOP)/ext/recover/sqlite3recover.h \
$(TOP)/src/test_windirent.c
$(TOP)/src/test_windirent.c
shell.c: $(SHELL_SRC) $(TOP)/tool/mkshellc.tcl has_tclsh84
$(TCLSH_CMD) $(TOP)/tool/mkshellc.tcl >shell.c
+1 -1
View File
@@ -1 +1 @@
3.44.2
3.45.0
+1 -1
View File
@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
# so that we create the export library with the dll.
#-----------------------------------------------------------------------
AC_INIT([sqlite],[3.44.2])
AC_INIT([sqlite],[3.45.0])
#--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars.
Vendored
+9 -9
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.44.2.
# Generated by GNU Autoconf 2.69 for sqlite 3.45.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.44.2'
PACKAGE_STRING='sqlite 3.44.2'
PACKAGE_VERSION='3.45.0'
PACKAGE_STRING='sqlite 3.45.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1472,7 +1472,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures sqlite 3.44.2 to adapt to many kinds of systems.
\`configure' configures sqlite 3.45.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1537,7 +1537,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.44.2:";;
short | recursive ) echo "Configuration of sqlite 3.45.0:";;
esac
cat <<\_ACEOF
@@ -1668,7 +1668,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
sqlite configure 3.44.2
sqlite configure 3.45.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2087,7 +2087,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.44.2, which was
It was created by sqlite $as_me 3.45.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -12481,7 +12481,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by sqlite $as_me 3.44.2, which was
This file was extended by sqlite $as_me 3.45.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -12547,7 +12547,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
sqlite config.status 3.44.2
sqlite config.status 3.45.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+1 -1
View File
@@ -74,7 +74,7 @@
# you don't need (for example BLT) by erasing or commenting out
# the corresponding code.
#
AC_INIT([sqlite],[m4_esyscmd(cat VERSION | tr -d '\n')])
AC_INIT([sqlite],m4_esyscmd(cat VERSION | tr -d '\n'))
dnl Make sure the local VERSION file matches this configure script
sqlite_version_sanity_check=`cat $srcdir/VERSION | tr -d '\n'`
+13 -1
View File
@@ -1,7 +1,7 @@
# Notes On Compiling SQLite On Windows 11
Here are step-by-step instructions on how to build SQLite from
canonical source on a new Windows 11 PC, as of 2023-08-16:
canonical source on a new Windows 11 PC, as of 2023-11-01:
1. Install Microsoft Visual Studio. The free "community edition"
will work fine. Do a standard install for C++ development.
@@ -84,6 +84,18 @@ following minor changes:
<li> `set PATH=c:\tcl32\bin;%PATH%`
</ul>
## Building a DLL
The command the developers use for building the deliverable DLL on the
[download page](https://sqlite.org/download.html) is as follows:
> ~~~~
nmake /f Makefile.msc sqlite3.dll USE_NATIVE_LIBPATHS=1 "OPTS=-DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS4=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_SESSION=1 -DSQLITE_ENABLE_PREUPDATE_HOOK=1 -DSQLITE_ENABLE_SERIALIZE=1 -DSQLITE_ENABLE_MATH_FUNCTIONS=1"
~~~~
That command generates both the sqlite3.dll and sqlite3.def files. The same
command works for both 32-bit and 64-bit builds.
## Statically Linking The TCL Library
Some utility programs associated with SQLite need to be linked
+69 -9
View File
@@ -2,6 +2,26 @@
# The testrunner.tcl Script
<ul type=none>
<li> 1. <a href=#overview>Overview</a>
<li> 2. <a href=#binary_tests>Binary Tests</a>
<ul type=none>
<li> 2.1. <a href=#organization_tests>Organization of Tcl Tests</a>
<li> 2.2. <a href=#run_tests>Commands to Run Tests</a>
<li> 2.3. <a href=#binary_test_failures>Investigating Binary Test Failures</a>
</ul>
<li> 3. <a href=#source_code_tests>Source Tests</a>
<ul type=none>
<li> 3.1. <a href=#commands_to_run_tests>Commands to Run SQLite Tests</a>
<li> 3.2. <a href=#zipvfs_tests>Running ZipVFS Tests</a>
<li> 3.3. <a href=#source_code_test_failures>Investigating Source Code Test Failures</a>
</ul>
<li> 4. <a href=#testrunner_options>Extra testrunner.tcl Options</a>
# 4. Extra testrunner.tcl Options
<li> 5. <a href=#cpu_cores>Controlling CPU Core Utilization</a>
</ul>
<a name=overview></a>
# 1. Overview
testrunner.tcl is a Tcl script used to run multiple SQLite tests using
@@ -44,6 +64,7 @@ Sometimes testrunner.tcl uses the [testfixture] binary that it is run with
to run tests (see "Binary Tests" below). Sometimes it builds testfixture and
other binaries in specific configurations to test (see "Source Tests").
<a name=binary_tests></a>
# 2. Binary Tests
The commands described in this section all run various combinations of the Tcl
@@ -61,6 +82,7 @@ these tests is therefore:
The following sub-sections describe the various options that can be
passed to testrunner.tcl to test binary testfixture builds.
<a name=organization_tests></a>
## 2.1. Organization of Tcl Tests
Tcl tests are stored in files that match the pattern *\*.test*. They are
@@ -91,6 +113,7 @@ Running **all** tests is to run all tests in the full test set, plus a dozen
or so permutations. The specific permutations that are run as part of "all"
are defined in file *testrunner_data.tcl*.
<a name=run_tests></a>
## 2.2. Commands to Run Tests
To run the "veryquick" test set, use either of the following:
@@ -114,6 +137,12 @@ a specified pattern (e.g. all tests that start with "fts5"), either of:
./testfixture $TESTDIR/testrunner.tcl 'fts5*'
```
Strictly speaking, for a test to be run the pattern must match the script
filename, not including the directory, using the rules of Tcl's
\[string match\] command. Except that before the matching is done, any "%"
characters specified as part of the pattern are transformed to "\*".
To run "all" tests (full + permutations):
```
@@ -141,6 +170,7 @@ Or, if the failure occured as part of a permutation:
TODO: An example instead of "$PERMUTATION" and $PATH\_TO\_SCRIPT?
<a name=source_code_tests></a>
# 3. Source Code Tests
The commands described in this section invoke the C compiler to build
@@ -159,7 +189,8 @@ shell that supports SQLite 3.31.1 or newer via "package require sqlite3".
TODO: ./configure + Makefile.msc build systems.
## Commands to Run SQLite Tests
<a name=commands_to_run_tests></a>
## 3.1. Commands to Run SQLite Tests
The **mdevtest** command is equivalent to running the veryquick tests and
the [make fuzztest] target once for each of two --enable-all builds - one
@@ -201,7 +232,18 @@ of the specific tests run.
tclsh $TESTDIR/testrunner.tcl release
```
## Running ZipVFS Tests
As with <a href=#source code tests>source code tests</a>, one or more patterns
may be appended to any of the above commands (mdevtest, sdevtest or release).
In that case only Tcl tests (no fuzz or other tests) that match the specified
pattern are run. For example, to run the just the Tcl rtree tests in all
builds and configurations supported by "release":
```
tclsh $TESTDIR/testrunner.tcl release rtree%
```
<a name=zipvfs_tests></a>
## 3.2. Running ZipVFS Tests
testrunner.tcl can build a zipvfs-enabled testfixture and use it to run
tests from the Zipvfs project with the following command:
@@ -217,7 +259,8 @@ test both SQLite and Zipvfs with a single command:
tclsh $TESTDIR/testrunner.tcl --zipvfs $PATH_TO_ZIPVFS mdevtest
```
## Investigating Source Code Test Failures
<a name=source_code_test_failures></a>
## 3.3. Investigating Source Code Test Failures
Investigating a test failure that occurs during source code testing is a
two step process:
@@ -244,9 +287,31 @@ target to build. This may be used either to run a [make] command test directly,
or else to build a testfixture (or testfixture.exe) binary with which to
run a Tcl test script, as <a href=#binary_test_failures>described above</a>.
<a name=testrunner_options></a>
# 4. Extra testrunner.tcl Options
The testrunner.tcl script options in this section may be used with both source
code and binary tests.
# 4. Controlling CPU Core Utilization
The **--buildonly** option instructs testrunner.tcl just to build the binaries
required by a test, not to run any actual tests. For example:
```
# Build binaries required by release test.
tclsh $TESTDIR/testrunner.tcl --buildonly release"
```
The **--dryrun** option prevents testrunner.tcl from building any binaries
or running any tests. Instead, it just writes the shell commands that it
would normally execute into the testrunner.log file. Example:
```
# Log the shell commmands that make up the mdevtest test.
tclsh $TESTDIR/testrunner.tcl --dryrun mdevtest"
```
<a name=cpu_cores></a>
# 5. Controlling CPU Core Utilization
When running either binary or source code tests, testrunner.tcl reports the
number of jobs it intends to use to stdout. e.g.
@@ -277,8 +342,3 @@ testrunner.log and testrunner.db files:
+6 -7
View File
@@ -549,12 +549,11 @@ zSkipValidUtf8(const char *z, int nAccept, long ccm){
#endif /*!(defined(SQLITE_CIO_NO_UTF8SCAN)&&defined(SQLITE_CIO_NO_TRANSLATE))*/
#ifndef SQLITE_CIO_NO_TRANSLATE
#ifdef CONSIO_SPUTB
# ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
assert(pfO!=0);
# if CIO_WIN_WC_XLATE
# if CIO_WIN_WC_XLATE
PerStreamTags pst = PST_INITIALIZER; /* for unknown streams */
PerStreamTags *ppst = getEmitStreamInfo(0, &pst, &pfO);
if( pstReachesConsole(ppst) ){
@@ -564,13 +563,13 @@ fPutbUtf8(FILE *pfO, const char *cBuf, int nAccept){
if( 0 == isKnownWritable(ppst->pf) ) restoreConsoleArb(ppst);
return rv;
}else {
# endif
# endif
return (int)fwrite(cBuf, 1, nAccept, pfO);
# if CIO_WIN_WC_XLATE
# if CIO_WIN_WC_XLATE
}
# endif
# endif
}
#endif /* defined(CONSIO_SPUTB) */
# endif
SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept){
+1 -1
View File
@@ -166,8 +166,8 @@ SQLITE_INTERNAL_LINKAGE int ePutsUtf8(const char *z);
#ifdef CONSIO_SPUTB
SQLITE_INTERNAL_LINKAGE int
fPutbUtf8(FILE *pfOut, const char *cBuf, int nAccept);
#endif
/* Like fPutbUtf8 except stream is always the designated output. */
#endif
SQLITE_INTERNAL_LINKAGE int
oPutbUtf8(const char *cBuf, int nAccept);
/* Like fPutbUtf8 except stream is always the designated error. */
+8
View File
@@ -211,6 +211,14 @@ static int fts5HighlightCb(
}
if( iPos==p->iRangeEnd ){
if( p->bOpen ){
if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
}
fts5HighlightAppend(&rc, p, p->zClose, -1);
p->bOpen = 0;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
}
+70 -27
View File
@@ -229,6 +229,12 @@ static const unsigned char sqlite3Utf8Trans1[] = {
#endif /* ifndef SQLITE_AMALGAMATION */
#define FTS5_SKIP_UTF8(zIn) { \
if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \
while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
} \
}
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -1264,6 +1270,7 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -1290,6 +1297,7 @@ static int fts5TriCreate(
}else{
int i;
pNew->bFold = 1;
pNew->iFoldParam = 0;
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
@@ -1298,10 +1306,21 @@ static int fts5TriCreate(
}else{
pNew->bFold = (zArg[0]=='0');
}
}else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
rc = SQLITE_ERROR;
}else{
pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
}
}else{
rc = SQLITE_ERROR;
}
}
if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
rc = SQLITE_ERROR;
}
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
@@ -1324,40 +1343,62 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
char *zOut = aBuf;
int ii;
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
while( 1 ){
char *zOut = aBuf;
int iStart = zIn - (const unsigned char*)pText;
const unsigned char *zNext;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
zNext = zIn;
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
/* Populate aBuf[] with the characters for the first trigram. */
for(ii=0; ii<3; ii++){
do {
aStart[ii] = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) return SQLITE_OK;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
WRITE_UTF8(zOut, iCode);
}
/* At the start of each iteration of this loop:
**
** aBuf: Contains 3 characters. The 3 characters of the next trigram.
** zOut: Points to the byte following the last character in aBuf.
** aStart[3]: Contains the byte offset in the input text corresponding
** to the start of each of the three characters in the buffer.
*/
assert( zIn<=zEof );
while( 1 ){
int iNext; /* Start of character following current tri */
const char *z1;
/* Read characters from the input up until the first non-diacritic */
do {
iNext = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
}else{
break;
}
if( zIn<zEof ){
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
WRITE_UTF8(zOut, iCode);
}else{
break;
}
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
if( rc!=SQLITE_OK ) break;
zIn = zNext;
if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
}while( iCode==0 );
/* Pass the current trigram back to fts5 */
rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
if( iCode==0 || rc!=SQLITE_OK ) break;
/* Remove the first character from buffer aBuf[]. Append the character
** with codepoint iCode. */
z1 = aBuf;
FTS5_SKIP_UTF8(z1);
memmove(aBuf, z1, zOut - z1);
zOut -= (z1 - aBuf);
WRITE_UTF8(zOut, iCode);
/* Update the aStart[] array */
aStart[0] = aStart[1];
aStart[1] = aStart[2];
aStart[2] = iNext;
}
return rc;
@@ -1380,7 +1421,9 @@ int sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
if( p->iFoldParam==0 ){
return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
}
}
return FTS5_PATTERN_NONE;
}
+89
View File
@@ -0,0 +1,89 @@
# 2023 Nov 03
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# Tests focusing on the built-in fts5 tokenizers.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5tokenizer2
# If SQLITE_ENABLE_FTS5 is defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
sqlite3_fts5_create_tokenizer db tst get_tst_tokenizer
proc get_tst_tokenizer {args} {
return "tst_tokenizer"
}
proc tst_tokenizer {flags txt} {
set token ""
set lTok [list]
foreach c [split $txt {}] {
if {$token==""} {
append token $c
} else {
set t1 [string is upper $token]
set t2 [string is upper $c]
if {$t1!=$t2} {
lappend lTok $token
set token ""
}
append token $c
}
}
if {$token!=""} { lappend lTok $token }
set iOff 0
foreach t $lTok {
set n [string length $t]
sqlite3_fts5_token $t $iOff [expr $iOff+$n]
incr iOff $n
}
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(t, tokenize=tst);
}
do_execsql_test 1.1 {
INSERT INTO t1 VALUES('AAdontBBmess');
}
do_execsql_test 1.2 {
SELECT snippet(t1, 0, '>', '<', '...', 4) FROM t1('BB');
} {AAdont>BB<mess}
do_execsql_test 1.3 {
SELECT highlight(t1, 0, '>', '<') FROM t1('BB');
} {AAdont>BB<mess}
do_execsql_test 1.4 {
SELECT highlight(t1, 0, '>', '<') FROM t1('AA');
} {>AA<dontBBmess}
do_execsql_test 1.5 {
SELECT highlight(t1, 0, '>', '<') FROM t1('dont');
} {AA>dont<BBmess}
do_execsql_test 1.6 {
SELECT highlight(t1, 0, '>', '<') FROM t1('mess');
} {AAdontBB>mess<}
do_execsql_test 1.7 {
SELECT highlight(t1, 0, '>', '<') FROM t1('BB mess');
} {AAdont>BBmess<}
finish_test
+109
View File
@@ -0,0 +1,109 @@
# 2023 October 24
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#*************************************************************************
#
# Tests for the fts5 "trigram" tokenizer.
#
source [file join [file dirname [info script]] fts5_common.tcl]
ifcapable !fts5 { finish_test ; return }
set ::testprefix fts5trigram2
do_execsql_test 1.0 "
CREATE VIRTUAL TABLE t1 USING fts5(y, tokenize='trigram remove_diacritics 1');
INSERT INTO t1 VALUES('abc\u0303defghijklm');
INSERT INTO t1 VALUES('a\u0303b\u0303c\u0303defghijklm');
"
do_execsql_test 1.1 {
SELECT highlight(t1, 0, '(', ')') FROM t1('abc');
} [list \
"(abc\u0303)defghijklm" \
"(a\u0303b\u0303c\u0303)defghijklm" \
]
do_execsql_test 1.2 {
SELECT highlight(t1, 0, '(', ')') FROM t1('bcde');
} [list \
"a(bc\u0303de)fghijklm" \
"a\u0303(b\u0303c\u0303de)fghijklm" \
]
do_execsql_test 1.3 {
SELECT highlight(t1, 0, '(', ')') FROM t1('cdef');
} [list \
"ab(c\u0303def)ghijklm" \
"a\u0303b\u0303(c\u0303def)ghijklm" \
]
do_execsql_test 1.4 {
SELECT highlight(t1, 0, '(', ')') FROM t1('def');
} [list \
"abc\u0303(def)ghijklm" \
"a\u0303b\u0303c\u0303(def)ghijklm" \
]
#-------------------------------------------------------------------------
do_catchsql_test 2.0 {
CREATE VIRTUAL TABLE t2 USING fts5(
z, tokenize='trigram case_sensitive 1 remove_diacritics 1'
);
} {1 {error in tokenizer constructor}}
do_execsql_test 2.1 {
CREATE VIRTUAL TABLE t2 USING fts5(
z, tokenize='trigram case_sensitive 0 remove_diacritics 1'
);
}
do_execsql_test 2.2 "
INSERT INTO t2 VALUES('\u00E3bcdef');
INSERT INTO t2 VALUES('b\u00E3cdef');
INSERT INTO t2 VALUES('bc\u00E3def');
INSERT INTO t2 VALUES('bcd\u00E3ef');
"
do_execsql_test 2.3 {
SELECT highlight(t2, 0, '(', ')') FROM t2('abc');
} "(\u00E3bc)def"
do_execsql_test 2.4 {
SELECT highlight(t2, 0, '(', ')') FROM t2('bac');
} "(b\u00E3c)def"
do_execsql_test 2.5 {
SELECT highlight(t2, 0, '(', ')') FROM t2('bca');
} "(bc\u00E3)def"
do_execsql_test 2.6 "
SELECT highlight(t2, 0, '(', ')') FROM t2('\u00E3bc');
" "(\u00E3bc)def"
#-------------------------------------------------------------------------
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE t3 USING fts5(
z, tokenize='trigram remove_diacritics 1'
);
} {}
do_execsql_test 3.1 "
INSERT INTO t3 VALUES ('\u0303abc\u0303');
"
do_execsql_test 3.2 {
SELECT highlight(t3, 0, '(', ')') FROM t3('abc');
} "\u0303(abc\u0303)"
#-------------------------------------------------------------------------
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE t4 USING fts5(z, tokenize=trigram);
} {}
breakpoint
do_execsql_test 4.1 {
INSERT INTO t4 VALUES('ABCD');
} {}
finish_test
+11 -4
View File
@@ -35,6 +35,8 @@ $(dir.bld.c):
javac.flags ?= -Xlint:unchecked -Xlint:deprecation
java.flags ?=
javac.flags += -encoding utf8
# -------------^^^^^^^^^^^^^^ required for Windows builds
jnicheck ?= 1
ifeq (1,$(jnicheck))
java.flags += -Xcheck:jni
@@ -79,6 +81,7 @@ $(bin.version-info): $(dir.tool)/version-info.c $(sqlite3.h) $(dir.top)/Makefile
# Be explicit about which Java files to compile so that we can work on
# in-progress files without requiring them to be in a compilable statae.
JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
Experimental.java \
NotNull.java \
Nullable.java \
) $(patsubst %,$(dir.src.capi)/%,\
@@ -91,7 +94,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
CollationNeededCallback.java \
CommitHookCallback.java \
ConfigLogCallback.java \
ConfigSqllogCallback.java \
ConfigSqlLogCallback.java \
NativePointerHolder.java \
OutputPointer.java \
PrepareMultiCallback.java \
@@ -110,6 +113,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
WindowFunction.java \
XDestroyCallback.java \
sqlite3.java \
sqlite3_blob.java \
sqlite3_context.java \
sqlite3_stmt.java \
sqlite3_value.java \
@@ -120,6 +124,7 @@ JAVA_FILES.main := $(patsubst %,$(dir.src.jni)/annotation/%,\
Sqlite.java \
SqliteException.java \
ValueHolder.java \
WindowFunction.java \
)
JAVA_FILES.unittest := $(patsubst %,$(dir.src.jni)/%,\
@@ -159,12 +164,13 @@ endif
CLASS_FILES :=
define CLASSFILE_DEPS
all: $(1).class
$(1).class: $(1).java
CLASS_FILES += $(1).class
endef
$(foreach B,$(basename \
$(JAVA_FILES.main) $(JAVA_FILES.unittest) $(JAVA_FILES.tester)),\
$(eval $(call CLASSFILE_DEPS,$(B))))
$(CLASS_FILES): $(JAVA_FILES) $(MAKEFILE)
$(CLASS_FILES): $(MAKEFILE)
$(bin.javac) $(javac.flags) -h $(dir.bld.c) -cp $(classpath) $(JAVA_FILES)
#.PHONY: classfiles
@@ -226,7 +232,8 @@ SQLITE_OPT += -DSQLITE_ENABLE_RTREE \
-DSQLITE_ENABLE_OFFSET_SQL_FUNC \
-DSQLITE_ENABLE_PREUPDATE_HOOK \
-DSQLITE_ENABLE_NORMALIZE \
-DSQLITE_ENABLE_SQLLOG
-DSQLITE_ENABLE_SQLLOG \
-DSQLITE_ENABLE_COLUMN_METADATA
endif
ifeq (1,$(opt.debug))
@@ -316,7 +323,7 @@ test-one: $(test.deps)
$(bin.java) $(test.flags.jvm) org.sqlite.jni.wrapper1.Tester2 $(Tester2.flags)
test-sqllog: $(test.deps)
@echo "Testing with -sqllog..."
$(bin.java) $(test.flags.jvm) -sqllog
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 $(Tester1.flags) -sqllog
test-mt: $(test.deps)
@echo "Testing in multi-threaded mode:";
$(bin.java) $(test.flags.jvm) org.sqlite.jni.capi.Tester1 \
+22 -19
View File
@@ -16,9 +16,8 @@ Technical support is available in the forum:
> **FOREWARNING:** this subproject is very much in development and
subject to any number of changes. Please do not rely on any
information about its API until this disclaimer is removed. The JNI
bindings released with version 3.43 are a "tech preview" and 3.44
will be "final," at which point strong backward compatibility
guarantees will apply.
bindings released with version 3.43 are a "tech preview." Once
finalized, strong backward compatibility guarantees will apply.
Project goals/requirements:
@@ -43,11 +42,13 @@ Non-goals:
- Creation of high-level OO wrapper APIs. Clients are free to create
them off of the C-style API.
- Virtual tables are unlikely to be supported due to the amount of
glue code needed to fit them into Java.
- Support for mixed-mode operation, where client code accesses SQLite
both via the Java-side API and the C API via their own native
code. In such cases, proxy functionalities (primarily callback
handler wrappers of all sorts) may fail because the C-side use of
the SQLite APIs will bypass those proxies.
code. Such cases would be a minefield of potential mis-interactions
between this project's JNI bindings and mixed-mode client code.
Hello World
@@ -123,15 +124,13 @@ sensible default argument values. In all such cases they are thin
proxies around the corresponding C APIs and do not introduce new
semantics.
In some very few cases, Java-specific capabilities have been added in
In a few cases, Java-specific capabilities have been added in
new APIs, all of which have "_java" somewhere in their names.
Examples include:
- `sqlite3_result_java_object()`
- `sqlite3_column_java_object()`
- `sqlite3_column_java_casted()`
- `sqlite3_value_java_object()`
- `sqlite3_value_java_casted()`
which, as one might surmise, collectively enable the passing of
arbitrary Java objects from user-defined SQL functions through to the
@@ -150,6 +149,9 @@ pending statements have been closed. Be aware that Java garbage
collection _cannot_ close a database or finalize a prepared statement.
Those things require explicit API calls.
Classes for which it is sensible support Java's `AutoCloseable`
interface so can be used with try-with-resources constructs.
Golden Rule #2: _Never_ Throw from Callbacks (Unless...)
------------------------------------------------------------------------
@@ -159,14 +161,15 @@ retain C-like semantics. For example, they are not permitted to throw
or propagate exceptions and must return error information (if any) via
result codes or `null`. The only cases where the C-style APIs may
throw is through client-side misuse, e.g. passing in a null where it
shouldn't be used. The APIs clearly mark function parameters which
should not be null, but does not actively defend itself against such
misuse. Some C-style APIs explicitly accept `null` as a no-op for
usability's sake, and some of the JNI APIs deliberately return an
error code, instead of segfaulting, when passed a `null`.
may cause a `NullPointerException`. The APIs clearly mark function
parameters which should not be null, but does not generally actively
defend itself against such misuse. Some C-style APIs explicitly accept
`null` as a no-op for usability's sake, and some of the JNI APIs
deliberately return an error code, instead of segfaulting, when passed
a `null`.
Client-defined callbacks _must never throw exceptions_ unless _very
explicitly documented_ as being throw-safe. Exceptions are generally
explitly documented_ as being throw-safe. Exceptions are generally
reserved for higher-level bindings which are constructed to
specifically deal with them and ensure that they do not leak C-level
resources. In some cases, callback handlers are permitted to throw, in
@@ -292,14 +295,14 @@ int sqlite3_create_function(sqlite3 db, String funcName, int nArgs,
`SQLFunction` is not used directly, but is instead instantiated via
one of its three subclasses:
- `SQLFunction.Scalar` implements simple scalar functions using but a
- `ScalarFunction` implements simple scalar functions using but a
single callback.
- `SQLFunction.Aggregate` implements aggregate functions using two
- `AggregateFunction` implements aggregate functions using two
callbacks.
- `SQLFunction.Window` implements window functions using four
- `WindowFunction` implements window functions using four
callbacks.
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/Tester1.java) for
Search [`Tester1.java`](/file/ext/jni/src/org/sqlite/jni/capi/Tester1.java) for
`SQLFunction` for how it's used.
Reminder: see the disclaimer at the top of this document regarding the
File diff suppressed because it is too large Load Diff
+108 -26
View File
@@ -427,8 +427,6 @@ extern "C" {
#define org_sqlite_jni_capi_CApi_SQLITE_OPEN_EXRESCODE 33554432L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_PERSISTENT 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NORMALIZE 2L
#undef org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB
#define org_sqlite_jni_capi_CApi_SQLITE_PREPARE_NO_VTAB 4L
#undef org_sqlite_jni_capi_CApi_SQLITE_OK
@@ -707,8 +705,12 @@ extern "C" {
#define org_sqlite_jni_capi_CApi_SQLITE_DETERMINISTIC 2048L
#undef org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY
#define org_sqlite_jni_capi_CApi_SQLITE_DIRECTONLY 524288L
#undef org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE
#define org_sqlite_jni_capi_CApi_SQLITE_SUBTYPE 1048576L
#undef org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS
#define org_sqlite_jni_capi_CApi_SQLITE_INNOCUOUS 2097152L
#undef org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE
#define org_sqlite_jni_capi_CApi_SQLITE_RESULT_SUBTYPE 16777216L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE
#define org_sqlite_jni_capi_CApi_SQLITE_INDEX_SCAN_UNIQUE 1L
#undef org_sqlite_jni_capi_CApi_SQLITE_INDEX_CONSTRAINT_EQ
@@ -775,6 +777,22 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_init
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1java_1uncache_1thread
(JNIEnv *, jclass);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_jni_supports_nio
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1supports_1nio
(JNIEnv *, jclass);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_jni_db_error
* Signature: (Lorg/sqlite/jni/capi/sqlite3;ILjava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1jni_1db_1error
(JNIEnv *, jclass, jobject, jint, jstring);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_aggregate_context
@@ -871,6 +889,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1int64
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1java_1object
(JNIEnv *, jclass, jlong, jint, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_bind_nio_buffer
* Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;ILjava/nio/ByteBuffer;II)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1bind_1nio_1buffer
(JNIEnv *, jclass, jobject, jint, jobject, jint, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_bind_null
@@ -975,6 +1001,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1open
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read
(JNIEnv *, jclass, jlong, jbyteArray, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_blob_read_nio_buffer
* Signature: (JILjava/nio/ByteBuffer;II)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1read_1nio_1buffer
(JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_blob_reopen
@@ -991,6 +1025,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1reopen
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write
(JNIEnv *, jclass, jlong, jbyteArray, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_blob_write_nio_buffer
* Signature: (JILjava/nio/ByteBuffer;II)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1blob_1write_1nio_1buffer
(JNIEnv *, jclass, jlong, jint, jobject, jint, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_busy_handler
@@ -1087,6 +1129,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1bytes16
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1count
(JNIEnv *, jclass, jlong);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_database_name
* Signature: (JI)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
(JNIEnv *, jclass, jlong, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_decltype
@@ -1119,6 +1169,14 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int
JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1int64
(JNIEnv *, jclass, jobject, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_java_object
* Signature: (JI)Ljava/lang/Object;
*/
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1java_1object
(JNIEnv *, jclass, jlong, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_name
@@ -1129,11 +1187,11 @@ JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1name
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_column_database_name
* Signature: (JI)Ljava/lang/String;
* Method: sqlite3_column_nio_buffer
* Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;I)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jstring JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1database_1name
(JNIEnv *, jclass, jlong, jint);
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1column_1nio_1buffer
(JNIEnv *, jclass, jobject, jint);
/*
* Class: org_sqlite_jni_capi_CApi
@@ -1225,26 +1283,26 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1complete
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_config
* Method: sqlite3_config__enable
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__I
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1enable
(JNIEnv *, jclass, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_config
* Signature: (Lorg/sqlite/jni/capi/ConfigSqllogCallback;)I
* Method: sqlite3_config__CONFIG_LOG
* Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigSqllogCallback_2
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1CONFIG_1LOG
(JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_config
* Signature: (Lorg/sqlite/jni/capi/ConfigLogCallback;)I
* Method: sqlite3_config__SQLLOG
* Signature: (Lorg/sqlite/jni/capi/ConfigSqlLogCallback;)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config__Lorg_sqlite_jni_capi_ConfigLogCallback_2
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1config_1_1SQLLOG
(JNIEnv *, jclass, jobject);
/*
@@ -1394,9 +1452,9 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1errcode
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_extended_result_codes
* Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)Z
* Signature: (Lorg/sqlite/jni/capi/sqlite3;Z)I
*/
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1extended_1result_1codes
(JNIEnv *, jclass, jobject, jboolean);
/*
@@ -1679,14 +1737,6 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error_1nom
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1error_1code
(JNIEnv *, jclass, jobject, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_null
* Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
*/
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
(JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_int
@@ -1711,6 +1761,30 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1int64
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1java_1object
(JNIEnv *, jclass, jobject, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_nio_buffer
* Signature: (Lorg/sqlite/jni/capi/sqlite3_context;Ljava/nio/ByteBuffer;II)V
*/
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1nio_1buffer
(JNIEnv *, jclass, jobject, jobject, jint, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_null
* Signature: (Lorg/sqlite/jni/capi/sqlite3_context;)V
*/
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1null
(JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_subtype
* Signature: (Lorg/sqlite/jni/capi/sqlite3_context;I)V
*/
JNIEXPORT void JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1result_1subtype
(JNIEnv *, jclass, jobject, jint);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_result_value
@@ -1850,10 +1924,10 @@ JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1status64
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_step
* Signature: (Lorg/sqlite/jni/capi/sqlite3_stmt;)I
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1step
(JNIEnv *, jclass, jobject);
(JNIEnv *, jclass, jlong);
/*
* Class: org_sqlite_jni_capi_CApi
@@ -2063,6 +2137,14 @@ JNIEXPORT jlong JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1int64
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1java_1object
(JNIEnv *, jclass, jlong);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_value_nio_buffer
* Signature: (Lorg/sqlite/jni/capi/sqlite3_value;)Ljava/nio/ByteBuffer;
*/
JNIEXPORT jobject JNICALL Java_org_sqlite_jni_capi_CApi_sqlite3_1value_1nio_1buffer
(JNIEnv *, jclass, jobject);
/*
* Class: org_sqlite_jni_capi_CApi
* Method: sqlite3_value_nochange
@@ -0,0 +1,30 @@
/*
** 2023-09-27
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the Experimental annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging methods, constructors, and types
which are expressly experimental and subject to any amount of
change or outright removal. Client code should not rely on such
features.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({
ElementType.METHOD,
ElementType.CONSTRUCTOR,
ElementType.TYPE
})
public @interface Experimental{}
@@ -9,21 +9,22 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the NotNull annotaion for the sqlite3 C API.
** This file houses the NotNull annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may not legally be
null or point to closed/finalized C-side resources.
<p>In the case of Java types which map directly to C struct types
(e.g. {@link org.sqlite.jni.sqlite3}, {@link
org.sqlite.jni.sqlite3_stmt}, and {@link
org.sqlite.jni.sqlite3_context}), a closed/finalized resource is
also considered to be null for purposes this annotation because the
C-side effect of passing such a handle is the same as if null is
passed.</p>
(e.g. {@link org.sqlite.jni.capi.sqlite3}, {@link
org.sqlite.jni.capi.sqlite3_stmt}, and {@link
org.sqlite.jni.capi.sqlite3_context}), a closed/finalized resource
is also considered to be null for purposes this annotation because
the C-side effect of passing such a handle is the same as if null
is passed.</p>
<p>When used in the context of Java interfaces which are called
from the C APIs, this annotation communicates that the C API will
@@ -31,12 +32,23 @@ package org.sqlite.jni.annotation;
<p>Passing a null, for this annotation's definition of null, for
any parameter marked with this annoation specifically invokes
undefined behavior.</p>
undefined behavior (see below).</p>
<p>Passing 0 (i.e. C NULL) or a negative value for any long-type
parameter marked with this annoation specifically invokes undefined
behavior. Such values are treated as C pointers in the JNI
layer.</p>
behavior (see below). Such values are treated as C pointers in the
JNI layer.</p>
<p><b>Undefined behaviour:</b> the JNI build uses the {@code
SQLITE_ENABLE_API_ARMOR} build flag, meaning that the C code
invoked with invalid NULL pointers and the like will not invoke
undefined behavior in the conventional C sense, but may, for
example, return result codes which are not documented for the
affected APIs or may otherwise behave unpredictably. In no known
cases will such arguments result in C-level code dereferencing a
NULL pointer or accessing out-of-bounds (or otherwise invalid)
memory. In other words, they may cause unexpected behavior but
should never cause an outright crash or security issue.</p>
<p>Note that the C-style API does not throw any exceptions on its
own because it has a no-throw policy in order to retain its C-style
@@ -48,12 +60,12 @@ package org.sqlite.jni.annotation;
code.</p>
<p>This annotation is solely for the use by the classes in the
org.sqlite package and subpackages, but is made public so that
org.sqlite.jni package and subpackages, but is made public so that
javadoc will link to it from the annotated functions. It is not
part of the public API and client-level code must not rely on
it.</p>
*/
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface NotNull{}
@@ -9,9 +9,10 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file houses the Nullable annotaion for the sqlite3 C API.
** This file houses the Nullable annotation for the sqlite3 C API.
*/
package org.sqlite.jni.annotation;
import java.lang.annotation.*;
/**
This annotation is for flagging parameters which may legally be
@@ -26,7 +27,7 @@ package org.sqlite.jni.annotation;
annotated functions. It is not part of the public API and
client-level code must not rely on it.
*/
@java.lang.annotation.Documented
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
@java.lang.annotation.Target(java.lang.annotation.ElementType.PARAMETER)
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.PARAMETER)
public @interface Nullable{}
@@ -42,9 +42,75 @@ public abstract class AggregateFunction<T> implements SQLFunction {
*/
public void xDestroy() {}
/**
PerContextState assists aggregate and window functions in
managing their accumulator state across calls to the UDF's
callbacks.
<p>T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
<p>If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
<p>This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
<p>This class is a helper providing commonly-needed functionality
- it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided {@link AggregateFunction} and {@link
WindowFunction} classes use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for the given context within the map, one is created
using the given initial value, else the existing one is used
and the 2nd argument is ignored. It returns a ValueHolder<T>
which can be used to modify that state directly without
requiring that the client update the underlying map's entry.
<p>The caller is obligated to eventually call
takeAggregateState() to clear the mapping.
*/
public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
final Long key = cx.getAggregateContext(true);
ValueHolder<T> rc = null==key ? null : map.get(key);
if( null==rc ){
map.put(key, rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with cx.getAggregateContext() from the map and
returns it, returning null if no other UDF method has been
called to set up such a mapping. The latter condition will be
the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(sqlite3_context cx){
final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
return null==h ? null : h.value;
}
}
/** Per-invocation state for the UDF. */
private final SQLFunction.PerContextState<T> map =
new SQLFunction.PerContextState<>();
private final PerContextState<T> map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
@@ -20,7 +20,8 @@ import org.sqlite.jni.annotation.*;
public interface AuthorizerCallback extends CallbackProxy {
/**
Must function as described for the C-level
sqlite3_set_authorizer() callback.
sqlite3_set_authorizer() callback. If it throws, the error is
converted to a db-level error and the exception is suppressed.
*/
int call(int opId, @Nullable String s1, @Nullable String s2,
@Nullable String s3, @Nullable String s4);
File diff suppressed because it is too large Load Diff
@@ -24,8 +24,9 @@ package org.sqlite.jni.capi;
propagated. For callback interfaces which support returning error
info to the core, the JNI binding will convert any exceptions to
C-level error information. For callback interfaces which do not
support, all exceptions will necessarily be suppressed in order to
retain the C-style no-throw semantics.
support returning error information, all exceptions will
necessarily be suppressed in order to retain the C-style no-throw
semantics and avoid invoking undefined behavior in the C layer.
<p>Callbacks of this style follow a common naming convention:
@@ -21,8 +21,9 @@ public interface CollationNeededCallback extends CallbackProxy {
Has the same semantics as the C-level sqlite3_create_collation()
callback.
<p>If it throws, the exception message is passed on to the db and
the exception is suppressed.
<p>Because the C API has no mechanism for reporting errors
from this callbacks, any exceptions thrown by this callback
are suppressed.
*/
int call(sqlite3 db, int eTextRep, String collationName);
void call(sqlite3 db, int eTextRep, String collationName);
}
@@ -19,7 +19,8 @@ package org.sqlite.jni.capi;
public interface CommitHookCallback extends CallbackProxy {
/**
Works as documented for the C-level sqlite3_commit_hook()
callback. Must not throw.
callback. If it throws, the exception is translated into
a db-level error.
*/
int call();
}
@@ -16,10 +16,10 @@ package org.sqlite.jni.capi;
/**
A callback for use with sqlite3_config().
*/
public interface ConfigSqllogCallback {
public interface ConfigSqlLogCallback {
/**
Must function as described for a C-level callback for
{@link CApi#sqlite3_config(ConfigSqllogCallback)}, with the slight signature change.
{@link CApi#sqlite3_config(ConfigSqlLogCallback)}, with the slight signature change.
*/
void call(sqlite3 db, String msg, int msgType );
}
@@ -228,4 +228,26 @@ public final class OutputPointer {
/** Sets the current value. */
public final void set(byte[] v){value = v;}
}
/**
Output pointer for use with native routines which return
blobs via java.nio.ByteBuffer.
See {@link org.sqlite.jni.capi.CApi#sqlite3_jni_supports_nio}
*/
public static final class ByteBuffer {
/**
This is public for ease of use. Accessors are provided for
consistency with the higher-level types.
*/
public java.nio.ByteBuffer value;
/** Initializes with the value null. */
public ByteBuffer(){this(null);}
/** Initializes with the value v. */
public ByteBuffer(java.nio.ByteBuffer v){value = v;}
/** Returns the current value. */
public final java.nio.ByteBuffer get(){return value;}
/** Sets the current value. */
public final void set(java.nio.ByteBuffer v){value = v;}
}
}
@@ -25,7 +25,10 @@ public interface PrepareMultiCallback extends CallbackProxy {
sqlite3_prepare_multi() will _not_ finalize st - it is up
to the call() implementation how st is handled.
Must return 0 on success or an SQLITE_... code on error.
Must return 0 on success or an SQLITE_... code on error. If it
throws, sqlite3_prepare_multi() will transform the exception into
a db-level error in order to retain the C-style error semantics
of the API.
See the {@link Finalize} class for a wrapper which finalizes the
statement after calling a proxy PrepareMultiCallback.
@@ -37,7 +40,7 @@ public interface PrepareMultiCallback extends CallbackProxy {
any sqlite3_stmt passed to its callback.
*/
public static final class Finalize implements PrepareMultiCallback {
private PrepareMultiCallback p;
private final PrepareMultiCallback p;
/**
p is the proxy to call() when this.call() is called.
*/
@@ -19,7 +19,8 @@ package org.sqlite.jni.capi;
public interface PreupdateHookCallback extends CallbackProxy {
/**
Must function as described for the C-level sqlite3_preupdate_hook()
callback.
callback. If it throws, the exception is translated to a
db-level error and the exception is suppressed.
*/
void call(sqlite3 db, int op, String dbName, String dbTable,
long iKey1, long iKey2 );
@@ -18,8 +18,9 @@ package org.sqlite.jni.capi;
*/
public interface RollbackHookCallback extends CallbackProxy {
/**
Works as documented for the C-level sqlite3_rollback_hook()
callback.
Must function as documented for the C-level sqlite3_rollback_hook()
callback. If it throws, the exception is translated into
a db-level error.
*/
void call();
}
@@ -33,71 +33,4 @@ package org.sqlite.jni.capi;
*/
public interface SQLFunction {
/**
PerContextState assists aggregate and window functions in
managing their accumulator state across calls to the UDF's
callbacks.
<p>T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
<p>If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
<p>This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
<p>This class is a helper providing commonly-needed functionality
- it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided {@link AggregateFunction} and {@link
WindowFunction} classes use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for the given context within the map, one is created
using the given initial value, else the existing one is used
and the 2nd argument is ignored. It returns a ValueHolder<T>
which can be used to modify that state directly without
requiring that the client update the underlying map's entry.
<p>The caller is obligated to eventually call
takeAggregateState() to clear the mapping.
*/
public ValueHolder<T> getAggregateState(sqlite3_context cx, T initialValue){
final Long key = cx.getAggregateContext(true);
ValueHolder<T> rc = null==key ? null : map.get(key);
if( null==rc ){
map.put(key, rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with cx.getAggregateContext() from the map and
returns it, returning null if no other UDF method has been
called to set up such a mapping. The latter condition will be
the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(sqlite3_context cx){
final ValueHolder<T> h = map.remove(cx.getAggregateContext(false));
return null==h ? null : h.value;
}
}
}
+281 -63
View File
@@ -38,6 +38,14 @@ import java.util.concurrent.Future;
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@interface SingleThreadOnly{}
/**
Annotation for Tester1 tests which must only be run if
sqlite3_jni_supports_nio() is true.
*/
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@interface RequiresJniNio{}
public class Tester1 implements Runnable {
//! True when running in multi-threaded mode.
private static boolean mtMode = false;
@@ -46,7 +54,7 @@ public class Tester1 implements Runnable {
//! True to shuffle the order of the tests.
private static boolean shuffle = false;
//! True to dump the list of to-run tests to stdout.
private static boolean listRunTests = false;
private static int listRunTests = 0;
//! True to squelch all out() and outln() output.
private static boolean quietMode = false;
//! Total number of runTests() calls.
@@ -327,7 +335,7 @@ public class Tester1 implements Runnable {
rc = sqlite3_prepare_v3(db, "INSERT INTO t2(a) VALUES(1),(2),(3)",
SQLITE_PREPARE_NORMALIZE, outStmt);
0, outStmt);
affirm(0 == rc);
stmt = outStmt.get();
affirm(0 != stmt.getNativePointer());
@@ -382,6 +390,15 @@ public class Tester1 implements Runnable {
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
affirm( sqlite3_stmt_readonly(stmt) );
affirm( !sqlite3_stmt_busy(stmt) );
if( sqlite3_compileoption_used("ENABLE_COLUMN_METADATA") ){
/* Unlike in native C code, JNI won't trigger an
UnsatisfiedLinkError until these are called (on Linux, at
least). */
affirm("t".equals(sqlite3_column_table_name(stmt,0)));
affirm("main".equals(sqlite3_column_database_name(stmt,0)));
affirm("a".equals(sqlite3_column_origin_name(stmt,0)));
}
int total2 = 0;
while( SQLITE_ROW == sqlite3_step(stmt) ){
affirm( sqlite3_stmt_busy(stmt) );
@@ -477,6 +494,7 @@ public class Tester1 implements Runnable {
stmt = prepare(db, "SELECT a FROM t ORDER BY a DESC;");
StringBuilder sbuf = new StringBuilder();
n = 0;
final boolean tryNio = sqlite3_jni_supports_nio();
while( SQLITE_ROW == sqlite3_step(stmt) ){
final sqlite3_value sv = sqlite3_value_dup(sqlite3_column_value(stmt,0));
final String txt = sqlite3_column_text16(stmt, 0);
@@ -491,6 +509,15 @@ public class Tester1 implements Runnable {
StandardCharsets.UTF_8)) );
affirm( txt.length() == sqlite3_value_bytes16(sv)/2 );
affirm( txt.equals(sqlite3_value_text16(sv)) );
if( tryNio ){
java.nio.ByteBuffer bu = sqlite3_value_nio_buffer(sv);
byte ba[] = sqlite3_value_blob(sv);
affirm( ba.length == bu.capacity() );
int i = 0;
for( byte b : ba ){
affirm( b == bu.get(i++) );
}
}
sqlite3_value_free(sv);
++n;
}
@@ -548,6 +575,79 @@ public class Tester1 implements Runnable {
sqlite3_close_v2(db);
}
@RequiresJniNio
private void testBindByteBuffer(){
/* TODO: these tests need to be much more extensive to check the
begin/end range handling. */
java.nio.ByteBuffer zeroCheck =
java.nio.ByteBuffer.allocateDirect(0);
affirm( null != zeroCheck );
zeroCheck = null;
sqlite3 db = createNewDb();
execSql(db, "CREATE TABLE t(a)");
final java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocateDirect(10);
buf.put((byte)0x31)/*note that we'll skip this one*/
.put((byte)0x32)
.put((byte)0x33)
.put((byte)0x34)
.put((byte)0x35)/*we'll skip this one too*/;
final int expectTotal = buf.get(1) + buf.get(2) + buf.get(3);
sqlite3_stmt stmt = prepare(db, "INSERT INTO t(a) VALUES(?);");
affirm( SQLITE_ERROR == sqlite3_bind_blob(stmt, 1, buf, -1, 0),
"Buffer offset may not be negative." );
affirm( 0 == sqlite3_bind_blob(stmt, 1, buf, 1, 3) );
affirm( SQLITE_DONE == sqlite3_step(stmt) );
sqlite3_finalize(stmt);
stmt = prepare(db, "SELECT a FROM t;");
int total = 0;
affirm( SQLITE_ROW == sqlite3_step(stmt) );
byte blob[] = sqlite3_column_blob(stmt, 0);
java.nio.ByteBuffer nioBlob =
sqlite3_column_nio_buffer(stmt, 0);
affirm(3 == blob.length);
affirm(blob.length == nioBlob.capacity());
affirm(blob.length == nioBlob.limit());
int i = 0;
for(byte b : blob){
affirm( i<=3 );
affirm(b == buf.get(1 + i));
affirm(b == nioBlob.get(i));
++i;
total += b;
}
affirm( SQLITE_DONE == sqlite3_step(stmt) );
sqlite3_finalize(stmt);
affirm(total == expectTotal);
SQLFunction func =
new ScalarFunction(){
public void xFunc(sqlite3_context cx, sqlite3_value[] args){
sqlite3_result_blob(cx, buf, 1, 3);
}
};
affirm( 0 == sqlite3_create_function(db, "myfunc", -1, SQLITE_UTF8, func) );
stmt = prepare(db, "SELECT myfunc()");
affirm( SQLITE_ROW == sqlite3_step(stmt) );
blob = sqlite3_column_blob(stmt, 0);
affirm(3 == blob.length);
i = 0;
total = 0;
for(byte b : blob){
affirm( i<=3 );
affirm(b == buf.get(1 + i++));
total += b;
}
affirm( SQLITE_DONE == sqlite3_step(stmt) );
sqlite3_finalize(stmt);
affirm(total == expectTotal);
sqlite3_close_v2(db);
}
private void testSql(){
sqlite3 db = createNewDb();
sqlite3_stmt stmt = prepare(db, "SELECT 1");
@@ -593,9 +693,9 @@ public class Tester1 implements Runnable {
};
final CollationNeededCallback collLoader = new CollationNeededCallback(){
@Override
public int call(sqlite3 dbArg, int eTextRep, String collationName){
public void call(sqlite3 dbArg, int eTextRep, String collationName){
affirm(dbArg == db/* as opposed to a temporary object*/);
return sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
sqlite3_create_collation(dbArg, "reversi", eTextRep, myCollation);
}
};
int rc = sqlite3_collation_needed(db, collLoader);
@@ -803,13 +903,17 @@ public class Tester1 implements Runnable {
affirm( 0==rc );
int n = 0;
if( SQLITE_ROW == sqlite3_step(stmt) ){
affirm( testResult.value == sqlite3_column_java_object(stmt, 0) );
affirm( testResult.value == sqlite3_column_java_object(stmt, 0, sqlite3.class) );
affirm( null == sqlite3_column_java_object(stmt, 0, sqlite3_stmt.class) );
affirm( null == sqlite3_column_java_object(stmt,1) );
final sqlite3_value v = sqlite3_column_value(stmt, 0);
affirm( testResult.value == sqlite3_value_java_object(v) );
affirm( testResult.value == sqlite3_value_java_casted(v, sqlite3.class) );
affirm( testResult.value == sqlite3_value_java_object(v, sqlite3.class) );
affirm( testResult.value ==
sqlite3_value_java_casted(v, testResult.value.getClass()) );
affirm( testResult.value == sqlite3_value_java_casted(v, Object.class) );
affirm( null == sqlite3_value_java_casted(v, String.class) );
sqlite3_value_java_object(v, testResult.value.getClass()) );
affirm( testResult.value == sqlite3_value_java_object(v, Object.class) );
affirm( null == sqlite3_value_java_object(v, String.class) );
++n;
}
sqlite3_finalize(stmt);
@@ -824,15 +928,28 @@ public class Tester1 implements Runnable {
// To confirm that xFinal() is called with no aggregate state
// when the corresponding result set is empty.
new ValueHolder<>(false);
final ValueHolder<sqlite3_value[]> neverEverDoThisInClientCode = new ValueHolder<>(null);
final ValueHolder<sqlite3_context> neverEverDoThisInClientCode2 = new ValueHolder<>(null);
SQLFunction func = new AggregateFunction<Integer>(){
@Override
public void xStep(sqlite3_context cx, sqlite3_value[] args){
if( null==neverEverDoThisInClientCode.value ){
/* !!!NEVER!!! hold a reference to an sqlite3_value or
sqlite3_context object like this in client code! They
are ONLY legal for the duration of their single
call. We do it here ONLY to test that the defenses
against clients doing this are working. */
neverEverDoThisInClientCode.value = args;
}
final ValueHolder<Integer> agg = this.getAggregateState(cx, 0);
agg.value += sqlite3_value_int(args[0]);
affirm( agg == this.getAggregateState(cx, 0) );
}
@Override
public void xFinal(sqlite3_context cx){
if( null==neverEverDoThisInClientCode2.value ){
neverEverDoThisInClientCode2.value = cx;
}
final Integer v = this.takeAggregateState(cx);
if(null == v){
xFinalNull.value = true;
@@ -857,6 +974,10 @@ public class Tester1 implements Runnable {
}
affirm( 1==n );
affirm(!xFinalNull.value);
affirm( null!=neverEverDoThisInClientCode.value );
affirm( null!=neverEverDoThisInClientCode2.value );
affirm( 0<neverEverDoThisInClientCode.value.length );
affirm( 0==neverEverDoThisInClientCode2.value.getNativePointer() );
sqlite3_reset(stmt);
affirm( 1==sqlite3_stmt_status(stmt, SQLITE_STMTSTATUS_RUN, false) );
// Ensure that the accumulator is reset on subsequent calls...
@@ -925,7 +1046,6 @@ public class Tester1 implements Runnable {
"ORDER BY x ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"+
") AS sum_y "+
"FROM twin ORDER BY x;");
affirm( 0 == rc );
int n = 0;
while( SQLITE_ROW == sqlite3_step(stmt) ){
final String s = sqlite3_column_text16(stmt, 0);
@@ -1028,48 +1148,48 @@ public class Tester1 implements Runnable {
@SingleThreadOnly /* because threads inherently break this test */
private static void testBusy(){
final String dbName = "_busy-handler.db";
final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
int rc = sqlite3_open(dbName, outDb);
++metrics.dbOpen;
affirm( 0 == rc );
final sqlite3 db1 = outDb.get();
execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
rc = sqlite3_open(dbName, outDb);
++metrics.dbOpen;
affirm( 0 == rc );
affirm( outDb.get() != db1 );
final sqlite3 db2 = outDb.get();
affirm( "main".equals( sqlite3_db_name(db1, 0) ) );
rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
affirm( "foo".equals( sqlite3_db_name(db1, 0) ) );
final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);
BusyHandlerCallback handler = new BusyHandlerCallback(){
@Override public int call(int n){
//outln("busy handler #"+n);
return n > 2 ? 0 : ++xBusyCalled.value;
}
};
rc = sqlite3_busy_handler(db2, handler);
affirm(0 == rc);
// Force a locked condition...
execSql(db1, "BEGIN EXCLUSIVE");
rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
affirm( SQLITE_BUSY == rc);
affirm( null == outStmt.get() );
affirm( 3 == xBusyCalled.value );
sqlite3_close_v2(db1);
sqlite3_close_v2(db2);
try{
final java.io.File f = new java.io.File(dbName);
f.delete();
}catch(Exception e){
/* ignore */
final OutputPointer.sqlite3 outDb = new OutputPointer.sqlite3();
final OutputPointer.sqlite3_stmt outStmt = new OutputPointer.sqlite3_stmt();
int rc = sqlite3_open(dbName, outDb);
++metrics.dbOpen;
affirm( 0 == rc );
final sqlite3 db1 = outDb.get();
execSql(db1, "CREATE TABLE IF NOT EXISTS t(a)");
rc = sqlite3_open(dbName, outDb);
++metrics.dbOpen;
affirm( 0 == rc );
affirm( outDb.get() != db1 );
final sqlite3 db2 = outDb.get();
affirm( "main".equals( sqlite3_db_name(db1, 0) ) );
rc = sqlite3_db_config(db1, SQLITE_DBCONFIG_MAINDBNAME, "foo");
affirm( sqlite3_db_filename(db1, "foo").endsWith(dbName) );
affirm( "foo".equals( sqlite3_db_name(db1, 0) ) );
affirm( SQLITE_MISUSE == sqlite3_db_config(db1, 0, 0, null) );
final ValueHolder<Integer> xBusyCalled = new ValueHolder<>(0);
BusyHandlerCallback handler = new BusyHandlerCallback(){
@Override public int call(int n){
//outln("busy handler #"+n);
return n > 2 ? 0 : ++xBusyCalled.value;
}
};
rc = sqlite3_busy_handler(db2, handler);
affirm(0 == rc);
// Force a locked condition...
execSql(db1, "BEGIN EXCLUSIVE");
rc = sqlite3_prepare_v2(db2, "SELECT * from t", outStmt);
affirm( SQLITE_BUSY == rc);
affirm( null == outStmt.get() );
affirm( 3 == xBusyCalled.value );
sqlite3_close_v2(db1);
sqlite3_close_v2(db2);
}finally{
try{(new java.io.File(dbName)).delete();}
catch(Exception e){/* ignore */}
}
}
@@ -1093,6 +1213,7 @@ public class Tester1 implements Runnable {
private void testCommitHook(){
final sqlite3 db = createNewDb();
sqlite3_extended_result_codes(db, true);
final ValueHolder<Integer> counter = new ValueHolder<>(0);
final ValueHolder<Integer> hookResult = new ValueHolder<>(0);
final CommitHookCallback theHook = new CommitHookCallback(){
@@ -1135,7 +1256,7 @@ public class Tester1 implements Runnable {
affirm( 5 == counter.value );
hookResult.value = SQLITE_ERROR;
int rc = execSql(db, false, "BEGIN; update t set a='j' where a='i'; COMMIT;");
affirm( SQLITE_CONSTRAINT == rc );
affirm( SQLITE_CONSTRAINT_COMMITHOOK == rc );
affirm( 6 == counter.value );
sqlite3_close_v2(db);
}
@@ -1354,6 +1475,9 @@ public class Tester1 implements Runnable {
authRc.value = SQLITE_DENY;
int rc = execSql(db, false, "UPDATE t SET a=2");
affirm( SQLITE_AUTH==rc );
sqlite3_set_authorizer(db, null);
rc = execSql(db, false, "UPDATE t SET a=2");
affirm( 0==rc );
// TODO: expand these tests considerably
sqlite3_close(db);
}
@@ -1415,7 +1539,7 @@ public class Tester1 implements Runnable {
val.value = 0;
final AutoExtensionCallback ax2 = new AutoExtensionCallback(){
@Override public synchronized int call(sqlite3 db){
@Override public int call(sqlite3 db){
++val.value;
return 0;
}
@@ -1626,7 +1750,7 @@ public class Tester1 implements Runnable {
sqlite3_finalize(stmt);
b = sqlite3_blob_open(db, "main", "t", "a",
sqlite3_last_insert_rowid(db), 1);
sqlite3_last_insert_rowid(db), 0);
affirm( null!=b );
rc = sqlite3_blob_reopen(b, 2);
affirm( 0==rc );
@@ -1636,6 +1760,86 @@ public class Tester1 implements Runnable {
affirm( 100==tgt[0] && 101==tgt[1] && 102==tgt[2], "DEF" );
rc = sqlite3_blob_close(b);
affirm( 0==rc );
if( !sqlite3_jni_supports_nio() ){
outln("WARNING: skipping tests for ByteBuffer-using sqlite3_blob APIs ",
"because this platform lacks that support.");
sqlite3_close_v2(db);
return;
}
/* Sanity checks for the java.nio.ByteBuffer-taking overloads of
sqlite3_blob_read/write(). */
execSql(db, "UPDATE t SET a=zeroblob(10)");
b = sqlite3_blob_open(db, "main", "t", "a", 1, 1);
affirm( null!=b );
java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocateDirect(10);
for( byte i = 0; i < 10; ++i ){
bb.put((int)i, (byte)(48+i & 0xff));
}
rc = sqlite3_blob_write(b, 1, bb, 1, 10);
affirm( rc==SQLITE_ERROR, "b length < (srcOffset + bb length)" );
rc = sqlite3_blob_write(b, -1, bb);
affirm( rc==SQLITE_ERROR, "Target offset may not be negative" );
rc = sqlite3_blob_write(b, 0, bb, -1, -1);
affirm( rc==SQLITE_ERROR, "Source offset may not be negative" );
rc = sqlite3_blob_write(b, 1, bb, 1, 8);
affirm( rc==0 );
// b's contents: 0 49 50 51 52 53 54 55 56 0
// ascii: 0 '1' '2' '3' '4' '5' '6' '7' '8' 0
byte br[] = new byte[10];
java.nio.ByteBuffer bbr =
java.nio.ByteBuffer.allocateDirect(bb.limit());
rc = sqlite3_blob_read( b, br, 0 );
affirm( rc==0 );
rc = sqlite3_blob_read( b, bbr );
affirm( rc==0 );
java.nio.ByteBuffer bbr2 = sqlite3_blob_read_nio_buffer(b, 0, 12);
affirm( null==bbr2, "Read size is too big");
bbr2 = sqlite3_blob_read_nio_buffer(b, -1, 3);
affirm( null==bbr2, "Source offset is negative");
bbr2 = sqlite3_blob_read_nio_buffer(b, 5, 6);
affirm( null==bbr2, "Read pos+size is too big");
bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 7);
affirm( null==bbr2, "Read pos+size is too big");
bbr2 = sqlite3_blob_read_nio_buffer(b, 4, 6);
affirm( null!=bbr2 );
java.nio.ByteBuffer bbr3 =
java.nio.ByteBuffer.allocateDirect(2 * bb.limit());
java.nio.ByteBuffer bbr4 =
java.nio.ByteBuffer.allocateDirect(5);
rc = sqlite3_blob_read( b, bbr3 );
affirm( rc==0 );
rc = sqlite3_blob_read( b, bbr4 );
affirm( rc==0 );
affirm( sqlite3_blob_bytes(b)==bbr3.limit() );
affirm( 5==bbr4.limit() );
sqlite3_blob_close(b);
affirm( 0==br[0] );
affirm( 0==br[9] );
affirm( 0==bbr.get(0) );
affirm( 0==bbr.get(9) );
affirm( bbr2.limit() == 6 );
affirm( 0==bbr3.get(0) );
{
Exception ex = null;
try{ bbr3.get(11); }
catch(Exception e){ex = e;}
affirm( ex instanceof IndexOutOfBoundsException,
"bbr3.limit() was reset by read()" );
ex = null;
}
affirm( 0==bbr4.get(0) );
for( int i = 1; i < 9; ++i ){
affirm( br[i] == 48 + i );
affirm( br[i] == bbr.get(i) );
affirm( br[i] == bbr3.get(i) );
if( i>3 ){
affirm( br[i] == bbr2.get(i-4) );
}
if( i < bbr4.limit() ){
affirm( br[i] == bbr4.get(i) );
}
}
sqlite3_close_v2(db);
}
@@ -1648,9 +1852,13 @@ public class Tester1 implements Runnable {
};
final List<sqlite3_stmt> liStmt = new ArrayList<sqlite3_stmt>();
final PrepareMultiCallback proxy = new PrepareMultiCallback.StepAll();
final ValueHolder<String> toss = new ValueHolder<>(null);
PrepareMultiCallback m = new PrepareMultiCallback() {
@Override public int call(sqlite3_stmt st){
liStmt.add(st);
if( null!=toss.value ){
throw new RuntimeException(toss.value);
}
return proxy.call(st);
}
};
@@ -1660,6 +1868,10 @@ public class Tester1 implements Runnable {
for( sqlite3_stmt st : liStmt ){
sqlite3_finalize(st);
}
toss.value = "This is an exception.";
rc = sqlite3_prepare_multi(db, "SELECT 1", m);
affirm( SQLITE_ERROR==rc );
affirm( sqlite3_errmsg(db).indexOf(toss.value)>0 );
sqlite3_close_v2(db);
}
@@ -1698,7 +1910,7 @@ public class Tester1 implements Runnable {
mlist = new ArrayList<>( testMethods.subList(0, testMethods.size()) );
java.util.Collections.shuffle(mlist);
}
if( listRunTests ){
if( (!fromThread && listRunTests>0) || listRunTests>1 ){
synchronized(this.getClass()){
if( !fromThread ){
out("Initial test"," list: ");
@@ -1760,8 +1972,11 @@ public class Tester1 implements Runnable {
-naps: sleep small random intervals between tests in order to add
some chaos for cross-thread contention.
-list-tests: outputs the list of tests being run, minus some
which are hard-coded. This is noisy in multi-threaded mode.
which are hard-coded. In multi-threaded mode, use this twice to
to emit the list run by each thread (which may differ from the initial
list, in particular if -shuffle is used).
-fail: forces an exception to be thrown during the test run. Use
with -shuffle to make its appearance unpredictable.
@@ -1790,7 +2005,7 @@ public class Tester1 implements Runnable {
}else if(arg.equals("shuffle")){
shuffle = true;
}else if(arg.equals("list-tests")){
listRunTests = true;
++listRunTests;
}else if(arg.equals("fail")){
forceFail = true;
}else if(arg.equals("sqllog")){
@@ -1809,7 +2024,7 @@ public class Tester1 implements Runnable {
if( sqlLog ){
if( sqlite3_compileoption_used("ENABLE_SQLLOG") ){
final ConfigSqllogCallback log = new ConfigSqllogCallback() {
final ConfigSqlLogCallback log = new ConfigSqlLogCallback() {
@Override public void call(sqlite3 db, String msg, int op){
switch(op){
case 0: outln("Opening db: ",db); break;
@@ -1820,7 +2035,7 @@ public class Tester1 implements Runnable {
};
int rc = sqlite3_config( log );
affirm( 0==rc );
rc = sqlite3_config( (ConfigSqllogCallback)null );
rc = sqlite3_config( (ConfigSqlLogCallback)null );
affirm( 0==rc );
rc = sqlite3_config( log );
affirm( 0==rc );
@@ -1858,18 +2073,20 @@ public class Tester1 implements Runnable {
if( forceFail ){
testMethods.add(m);
}
}else if( m.isAnnotationPresent( RequiresJniNio.class )
&& !sqlite3_jni_supports_nio() ){
outln("Skipping test for lack of JNI java.nio.ByteBuffer support: ",
name,"()\n");
++nSkipped;
}else if( !m.isAnnotationPresent( ManualTest.class ) ){
if( nThread>1 && m.isAnnotationPresent( SingleThreadOnly.class ) ){
if( 0==nSkipped++ ){
out("Skipping tests in multi-thread mode:");
}
out(" "+name+"()");
out("Skipping test in multi-thread mode: ",name,"()\n");
++nSkipped;
}else if( name.startsWith("test") ){
testMethods.add(m);
}
}
}
if( nSkipped>0 ) out("\n");
}
final long timeStart = System.currentTimeMillis();
@@ -1901,6 +2118,7 @@ public class Tester1 implements Runnable {
sqlite3_libversion_number(),"\n",
sqlite3_libversion(),"\n",SQLITE_SOURCE_ID,"\n",
"SQLITE_THREADSAFE=",sqlite3_threadsafe());
outln("JVM NIO support? ",sqlite3_jni_supports_nio() ? "YES" : "NO");
final boolean showLoopCount = (nRepeat>1 && nThread>1);
if( showLoopCount ){
outln("Running ",nRepeat," loop(s) with ",nThread," thread(s) each.");
@@ -19,7 +19,8 @@ package org.sqlite.jni.capi;
public interface UpdateHookCallback extends CallbackProxy {
/**
Must function as described for the C-level sqlite3_update_hook()
callback.
callback. If it throws, the exception is translated into
a db-level error.
*/
void call(int opId, String dbName, String tableName, long rowId);
}
@@ -9,14 +9,16 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains a set of tests for the sqlite3 JNI bindings.
** This file contains the ValueHolder utility class for the sqlite3
** JNI bindings.
*/
package org.sqlite.jni.capi;
/**
A helper class which simply holds a single value. Its primary use
is for communicating values out of anonymous classes, as doing so
requires a "final" reference.
requires a "final" reference, as well as communicating aggregate
SQL function state across calls to such functions.
*/
public class ValueHolder<T> {
public T value;
+1 -1
View File
@@ -38,6 +38,6 @@ public final class sqlite3 extends NativePointerHolder<sqlite3>
}
@Override public void close(){
CApi.sqlite3_close_v2(this.clearNativePointer());
CApi.sqlite3_close_v2(this);
}
}
@@ -25,7 +25,6 @@ public final class sqlite3_blob extends NativePointerHolder<sqlite3_blob>
private sqlite3_blob(){}
@Override public void close(){
CApi.sqlite3_blob_close(this.clearNativePointer());
CApi.sqlite3_blob_close(this);
}
}
@@ -25,6 +25,6 @@ public final class sqlite3_stmt extends NativePointerHolder<sqlite3_stmt>
private sqlite3_stmt(){}
@Override public void close(){
CApi.sqlite3_finalize(this.clearNativePointer());
CApi.sqlite3_finalize(this);
}
}
@@ -12,10 +12,6 @@
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.annotation.*;
import org.sqlite.jni.capi.sqlite3_context;
import org.sqlite.jni.capi.sqlite3_value;
/**
EXPERIMENTAL/INCOMPLETE/UNTESTED
@@ -51,9 +47,75 @@ public abstract class AggregateFunction<T> implements SqlFunction {
*/
public void xDestroy() {}
/**
PerContextState assists aggregate and window functions in
managing their accumulator state across calls to the UDF's
callbacks.
<p>T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
<p>If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
<p>This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
<p>This class is a helper providing commonly-needed functionality
- it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided {@link AggregateFunction} and {@link
WindowFunction} classes use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for the given context within the map, one is created
using the given initial value, else the existing one is used
and the 2nd argument is ignored. It returns a ValueHolder<T>
which can be used to modify that state directly without
requiring that the client update the underlying map's entry.
<p>The caller is obligated to eventually call
takeAggregateState() to clear the mapping.
*/
public ValueHolder<T> getAggregateState(SqlFunction.Arguments args, T initialValue){
final Long key = args.getContext().getAggregateContext(true);
ValueHolder<T> rc = null==key ? null : map.get(key);
if( null==rc ){
map.put(key, rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with with the arguments' aggregate context from the
map and returns it, returning null if no other UDF method has
been called to set up such a mapping. The latter condition will
be the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(SqlFunction.Arguments args){
final ValueHolder<T> h = map.remove(args.getContext().getAggregateContext(false));
return null==h ? null : h.value;
}
}
/** Per-invocation state for the UDF. */
private final SqlFunction.PerContextState<T> map =
new SqlFunction.PerContextState<>();
private final PerContextState<T> map = new PerContextState<>();
/**
To be called from the implementation's xStep() method, as well
@@ -22,6 +22,14 @@ import org.sqlite.jni.capi.sqlite3_value;
*/
public interface SqlFunction {
public static final int DETERMINISTIC = CApi.SQLITE_DETERMINISTIC;
public static final int INNOCUOUS = CApi.SQLITE_INNOCUOUS;
public static final int DIRECTONLY = CApi.SQLITE_DIRECTONLY;
public static final int SUBTYPE = CApi.SQLITE_SUBTYPE;
public static final int RESULT_SUBTYPE = CApi.SQLITE_RESULT_SUBTYPE;
public static final int UTF8 = CApi.SQLITE_UTF8;
public static final int UTF16 = CApi.SQLITE_UTF16;
/**
The Arguments type is an abstraction on top of the lower-level
UDF function argument types. It provides _most_ of the functionality
@@ -45,12 +53,118 @@ public interface SqlFunction {
*/
Arguments(sqlite3_context cx, sqlite3_value args[]){
this.cx = cx;
this.args = args==null ? new sqlite3_value[0] : args;;
this.args = args==null ? new sqlite3_value[0] : args;
this.length = this.args.length;
}
/**
Wrapper for a single SqlFunction argument. Primarily intended
Returns the sqlite3_value at the given argument index or throws
an IllegalArgumentException exception if ndx is out of range.
*/
private sqlite3_value valueAt(int ndx){
if(ndx<0 || ndx>=args.length){
throw new IllegalArgumentException(
"SQL function argument index "+ndx+" is out of range."
);
}
return args[ndx];
}
//! Returns the underlying sqlite3_context for these arguments.
sqlite3_context getContext(){return cx;}
/**
Returns the Sqlite (db) object associated with this UDF call,
or null if the UDF is somehow called without such an object or
the db has been closed in an untimely manner (e.g. closed by a
UDF call).
*/
public Sqlite getDb(){
return Sqlite.fromNative( CApi.sqlite3_context_db_handle(cx) );
}
public int getArgCount(){ return args.length; }
public int getInt(int argNdx){return CApi.sqlite3_value_int(valueAt(argNdx));}
public long getInt64(int argNdx){return CApi.sqlite3_value_int64(valueAt(argNdx));}
public double getDouble(int argNdx){return CApi.sqlite3_value_double(valueAt(argNdx));}
public byte[] getBlob(int argNdx){return CApi.sqlite3_value_blob(valueAt(argNdx));}
public byte[] getText(int argNdx){return CApi.sqlite3_value_text(valueAt(argNdx));}
public String getText16(int argNdx){return CApi.sqlite3_value_text16(valueAt(argNdx));}
public int getBytes(int argNdx){return CApi.sqlite3_value_bytes(valueAt(argNdx));}
public int getBytes16(int argNdx){return CApi.sqlite3_value_bytes16(valueAt(argNdx));}
public Object getObject(int argNdx){return CApi.sqlite3_value_java_object(valueAt(argNdx));}
public <T> T getObject(int argNdx, Class<T> type){
return CApi.sqlite3_value_java_object(valueAt(argNdx), type);
}
public int getType(int argNdx){return CApi.sqlite3_value_type(valueAt(argNdx));}
public int getSubtype(int argNdx){return CApi.sqlite3_value_subtype(valueAt(argNdx));}
public int getNumericType(int argNdx){return CApi.sqlite3_value_numeric_type(valueAt(argNdx));}
public int getNoChange(int argNdx){return CApi.sqlite3_value_nochange(valueAt(argNdx));}
public boolean getFromBind(int argNdx){return CApi.sqlite3_value_frombind(valueAt(argNdx));}
public int getEncoding(int argNdx){return CApi.sqlite3_value_encoding(valueAt(argNdx));}
public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); }
public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); }
public void resultDouble(double v){ CApi.sqlite3_result_double(cx, v); }
public void resultError(String msg){CApi.sqlite3_result_error(cx, msg);}
public void resultError(Exception e){CApi.sqlite3_result_error(cx, e);}
public void resultErrorTooBig(){CApi.sqlite3_result_error_toobig(cx);}
public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
public void resultNull(){CApi.sqlite3_result_null(cx);}
/**
Analog to sqlite3_result_value(), using the Value object at the
given argument index.
*/
public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
public void resultSubtype(int subtype){CApi.sqlite3_result_subtype(cx, subtype);}
public void resultZeroBlob(long n){
// Throw on error? If n is too big,
// sqlite3_result_error_toobig() is automatically called.
CApi.sqlite3_result_zeroblob64(cx, n);
}
public void resultBlob(byte[] blob){CApi.sqlite3_result_blob(cx, blob);}
public void resultText(byte[] utf8){CApi.sqlite3_result_text(cx, utf8);}
public void resultText(String txt){CApi.sqlite3_result_text(cx, txt);}
public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}
/**
Callbacks should invoke this on OOM errors, instead of throwing
OutOfMemoryError, because the latter cannot be propagated
through the C API.
*/
public void resultNoMem(){CApi.sqlite3_result_error_nomem(cx);}
/**
Analog to sqlite3_set_auxdata() but throws if argNdx is out of
range.
*/
public void setAuxData(int argNdx, Object o){
/* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html
The value of the N parameter to these interfaces should be
non-negative. Future enhancements may make use of negative N
values to define new kinds of function caching behavior.
*/
valueAt(argNdx);
CApi.sqlite3_set_auxdata(cx, argNdx, o);
}
/**
Analog to sqlite3_get_auxdata() but throws if argNdx is out of
range.
*/
public Object getAuxData(int argNdx){
valueAt(argNdx);
return CApi.sqlite3_get_auxdata(cx, argNdx);
}
/**
Represents a single SqlFunction argument. Primarily intended
for use with the Arguments class's Iterable interface.
*/
public final static class Arg {
@@ -72,7 +186,7 @@ public interface SqlFunction {
public int getBytes(){return a.getBytes(ndx);}
public int getBytes16(){return a.getBytes16(ndx);}
public Object getObject(){return a.getObject(ndx);}
public <T> T getObjectCasted(Class<T> type){ return a.getObjectCasted(ndx, type); }
public <T> T getObject(Class<T> type){ return a.getObject(ndx, type); }
public int getType(){return a.getType(ndx);}
public Object getAuxData(){return a.getAuxData(ndx);}
public void setAuxData(Object o){a.setAuxData(ndx, o);}
@@ -87,147 +201,6 @@ public interface SqlFunction {
return java.util.Arrays.stream(proxies).iterator();
}
/**
Returns the sqlite3_value at the given argument index or throws
an IllegalArgumentException exception if ndx is out of range.
*/
private sqlite3_value valueAt(int ndx){
if(ndx<0 || ndx>=args.length){
throw new IllegalArgumentException(
"SQL function argument index "+ndx+" is out of range."
);
}
return args[ndx];
}
sqlite3_context getContext(){return cx;}
public int getArgCount(){ return args.length; }
public int getInt(int arg){return CApi.sqlite3_value_int(valueAt(arg));}
public long getInt64(int arg){return CApi.sqlite3_value_int64(valueAt(arg));}
public double getDouble(int arg){return CApi.sqlite3_value_double(valueAt(arg));}
public byte[] getBlob(int arg){return CApi.sqlite3_value_blob(valueAt(arg));}
public byte[] getText(int arg){return CApi.sqlite3_value_text(valueAt(arg));}
public String getText16(int arg){return CApi.sqlite3_value_text16(valueAt(arg));}
public int getBytes(int arg){return CApi.sqlite3_value_bytes(valueAt(arg));}
public int getBytes16(int arg){return CApi.sqlite3_value_bytes16(valueAt(arg));}
public Object getObject(int arg){return CApi.sqlite3_value_java_object(valueAt(arg));}
public <T> T getObjectCasted(int arg, Class<T> type){
return CApi.sqlite3_value_java_casted(valueAt(arg), type);
}
public int getType(int arg){return CApi.sqlite3_value_type(valueAt(arg));}
public int getSubtype(int arg){return CApi.sqlite3_value_subtype(valueAt(arg));}
public int getNumericType(int arg){return CApi.sqlite3_value_numeric_type(valueAt(arg));}
public int getNoChange(int arg){return CApi.sqlite3_value_nochange(valueAt(arg));}
public boolean getFromBind(int arg){return CApi.sqlite3_value_frombind(valueAt(arg));}
public int getEncoding(int arg){return CApi.sqlite3_value_encoding(valueAt(arg));}
public void resultInt(int v){ CApi.sqlite3_result_int(cx, v); }
public void resultInt64(long v){ CApi.sqlite3_result_int64(cx, v); }
public void resultDouble(double v){ CApi.sqlite3_result_double(cx, v); }
public void resultError(String msg){CApi.sqlite3_result_error(cx, msg);}
public void resultError(Exception e){CApi.sqlite3_result_error(cx, e);}
public void resultErrorTooBig(){CApi.sqlite3_result_error_toobig(cx);}
public void resultErrorCode(int rc){CApi.sqlite3_result_error_code(cx, rc);}
public void resultObject(Object o){CApi.sqlite3_result_java_object(cx, o);}
public void resultNull(){CApi.sqlite3_result_null(cx);}
public void resultArg(int argNdx){CApi.sqlite3_result_value(cx, valueAt(argNdx));}
public void resultZeroBlob(long n){
// Throw on error? If n is too big,
// sqlite3_result_error_toobig() is automatically called.
CApi.sqlite3_result_zeroblob64(cx, n);
}
public void resultBlob(byte[] blob){CApi.sqlite3_result_blob(cx, blob);}
public void resultText(byte[] utf8){CApi.sqlite3_result_text(cx, utf8);}
public void resultText(String txt){CApi.sqlite3_result_text(cx, txt);}
public void resultText16(byte[] utf16){CApi.sqlite3_result_text16(cx, utf16);}
public void resultText16(String txt){CApi.sqlite3_result_text16(cx, txt);}
public void setAuxData(int arg, Object o){
/* From the API docs: https://www.sqlite.org/c3ref/get_auxdata.html
The value of the N parameter to these interfaces should be
non-negative. Future enhancements may make use of negative N
values to define new kinds of function caching behavior.
*/
valueAt(arg);
CApi.sqlite3_set_auxdata(cx, arg, o);
}
public Object getAuxData(int arg){
valueAt(arg);
return CApi.sqlite3_get_auxdata(cx, arg);
}
}
/**
PerContextState assists aggregate and window functions in
managing their accumulator state across calls to the UDF's
callbacks.
<p>T must be of a type which can be legally stored as a value in
java.util.HashMap<KeyType,T>.
<p>If a given aggregate or window function is called multiple times
in a single SQL statement, e.g. SELECT MYFUNC(A), MYFUNC(B)...,
then the clients need some way of knowing which call is which so
that they can map their state between their various UDF callbacks
and reset it via xFinal(). This class takes care of such
mappings.
<p>This class works by mapping
sqlite3_context.getAggregateContext() to a single piece of
state, of a client-defined type (the T part of this class), which
persists across a "matching set" of the UDF's callbacks.
<p>This class is a helper providing commonly-needed functionality
- it is not required for use with aggregate or window functions.
Client UDFs are free to perform such mappings using custom
approaches. The provided {@link AggregateFunction} and {@link
WindowFunction} classes use this.
*/
public static final class PerContextState<T> {
private final java.util.Map<Long,ValueHolder<T>> map
= new java.util.HashMap<>();
/**
Should be called from a UDF's xStep(), xValue(), and xInverse()
methods, passing it that method's first argument and an initial
value for the persistent state. If there is currently no
mapping for the given context within the map, one is created
using the given initial value, else the existing one is used
and the 2nd argument is ignored. It returns a ValueHolder<T>
which can be used to modify that state directly without
requiring that the client update the underlying map's entry.
<p>The caller is obligated to eventually call
takeAggregateState() to clear the mapping.
*/
public ValueHolder<T> getAggregateState(SqlFunction.Arguments args, T initialValue){
final Long key = args.getContext().getAggregateContext(true);
ValueHolder<T> rc = null==key ? null : map.get(key);
if( null==rc ){
map.put(key, rc = new ValueHolder<>(initialValue));
}
return rc;
}
/**
Should be called from a UDF's xFinal() method and passed that
method's first argument. This function removes the value
associated with with the arguments' aggregate context from the
map and returns it, returning null if no other UDF method has
been called to set up such a mapping. The latter condition will
be the case if a UDF is used in a statement which has no result
rows.
*/
public T takeAggregateState(SqlFunction.Arguments args){
final ValueHolder<T> h = map.remove(args.getContext().getAggregateContext(false));
return null==h ? null : h.value;
}
}
/**
@@ -235,7 +208,7 @@ public interface SqlFunction {
for use with the org.sqlite.jni.capi.ScalarFunction interface.
*/
static final class ScalarAdapter extends org.sqlite.jni.capi.ScalarFunction {
final ScalarFunction impl;
private final ScalarFunction impl;
ScalarAdapter(ScalarFunction impl){
this.impl = impl;
}
@@ -261,8 +234,9 @@ public interface SqlFunction {
Internal-use adapter for wrapping this package's AggregateFunction
for use with the org.sqlite.jni.capi.AggregateFunction interface.
*/
static final class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
final AggregateFunction impl;
static /*cannot be final without duplicating the whole body in WindowAdapter*/
class AggregateAdapter extends org.sqlite.jni.capi.AggregateFunction {
private final AggregateFunction impl;
AggregateAdapter(AggregateFunction impl){
this.impl = impl;
}
@@ -282,8 +256,9 @@ public interface SqlFunction {
}
/**
As for the xFinal() argument of the C API's sqlite3_create_function().
If the proxied function throws, it is translated into a sqlite3_result_error().
As for the xFinal() argument of the C API's
sqlite3_create_function(). If the proxied function throws, it
is translated into a sqlite3_result_error().
*/
public void xFinal(sqlite3_context cx){
try{
@@ -298,4 +273,46 @@ public interface SqlFunction {
}
}
/**
Internal-use adapter for wrapping this package's WindowFunction
for use with the org.sqlite.jni.capi.WindowFunction interface.
*/
static final class WindowAdapter extends AggregateAdapter {
private final WindowFunction impl;
WindowAdapter(WindowFunction impl){
super(impl);
this.impl = impl;
}
/**
Proxies this.impl.xInverse(), adapting the call arguments to that
function's signature. If the proxied function throws, it is
translated to sqlite_result_error() with the exception's
message.
*/
public void xInverse(sqlite3_context cx, sqlite3_value[] args){
try{
impl.xInverse( new SqlFunction.Arguments(cx, args) );
}catch(Exception e){
CApi.sqlite3_result_error(cx, e);
}
}
/**
As for the xValue() argument of the C API's sqlite3_create_window_function().
If the proxied function throws, it is translated into a sqlite3_result_error().
*/
public void xValue(sqlite3_context cx){
try{
impl.xValue( new SqlFunction.Arguments(cx, null) );
}catch(Exception e){
CApi.sqlite3_result_error(cx, e);
}
}
public void xDestroy(){
impl.xDestroy();
}
}
}
File diff suppressed because it is too large Load Diff
@@ -12,7 +12,7 @@
** This file is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
import static org.sqlite.jni.capi.CApi.*;
import org.sqlite.jni.capi.CApi;
import org.sqlite.jni.capi.sqlite3;
/**
@@ -22,10 +22,10 @@ import org.sqlite.jni.capi.sqlite3;
and C via JNI.
*/
public final class SqliteException extends java.lang.RuntimeException {
int errCode = SQLITE_ERROR;
int xerrCode = SQLITE_ERROR;
int errOffset = -1;
int sysErrno = 0;
private int errCode = CApi.SQLITE_ERROR;
private int xerrCode = CApi.SQLITE_ERROR;
private int errOffset = -1;
private int sysErrno = 0;
/**
Records the given error string and uses SQLITE_ERROR for both the
@@ -38,28 +38,31 @@ public final class SqliteException extends java.lang.RuntimeException {
/**
Uses sqlite3_errstr(sqlite3ResultCode) for the error string and
sets both the error code and extended error code to the given
value.
value. This approach includes no database-level information and
systemErrno() will be 0, so is intended only for use with sqlite3
APIs for which a result code is not an error but which the
higher-level wrapper should treat as one.
*/
public SqliteException(int sqlite3ResultCode){
super(sqlite3_errstr(sqlite3ResultCode));
super(CApi.sqlite3_errstr(sqlite3ResultCode));
errCode = xerrCode = sqlite3ResultCode;
}
/**
Records the current error state of db (which must not be null and
must refer to an opened db object). Note that this does NOT close
must refer to an opened db object). Note that this does not close
the db.
Design note: closing the db on error is likely only useful during
Design note: closing the db on error is really only useful during
a failed db-open operation, and the place(s) where that can
happen are inside this library, not client-level code.
*/
SqliteException(sqlite3 db){
super(sqlite3_errmsg(db));
errCode = sqlite3_errcode(db);
xerrCode = sqlite3_extended_errcode(db);
errOffset = sqlite3_error_offset(db);
sysErrno = sqlite3_system_errno(db);
super(CApi.sqlite3_errmsg(db));
errCode = CApi.sqlite3_errcode(db);
xerrCode = CApi.sqlite3_extended_errcode(db);
errOffset = CApi.sqlite3_error_offset(db);
sysErrno = CApi.sqlite3_system_errno(db);
}
/**
@@ -71,7 +74,7 @@ public final class SqliteException extends java.lang.RuntimeException {
}
public SqliteException(Sqlite.Stmt stmt){
this( stmt.db() );
this(stmt.getDb());
}
public int errcode(){ return errCode; }
File diff suppressed because it is too large Load Diff
@@ -9,13 +9,13 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains a set of tests for the sqlite3 JNI bindings.
** This file contains the ValueHolder utility class.
*/
package org.sqlite.jni.wrapper1;
/**
A helper class which simply holds a single value. Its primary use
is for communicating values out of anonymous classes, as doing so
is for communicating values out of anonymous callbacks, as doing so
requires a "final" reference.
*/
public class ValueHolder<T> {
@@ -0,0 +1,42 @@
/*
** 2023-10-16
**
** 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 is part of the wrapper1 interface for sqlite3.
*/
package org.sqlite.jni.wrapper1;
/**
A SqlFunction implementation for window functions. The T type
represents the type of data accumulated by this function while it
works. e.g. a SUM()-like UDF might use Integer or Long and a
CONCAT()-like UDF might use a StringBuilder or a List<String>.
*/
public abstract class WindowFunction<T> extends AggregateFunction<T> {
/**
As for the xInverse() argument of the C API's
sqlite3_create_window_function(). If this function throws, the
exception is reported via sqlite3_result_error().
*/
public abstract void xInverse(SqlFunction.Arguments args);
/**
As for the xValue() argument of the C API's
sqlite3_create_window_function(). If this function throws, it is
translated into sqlite3_result_error().
Note that the passed-in object will not actually contain any
arguments for xValue() but will contain the context object needed
for setting the call's result or error state.
*/
public abstract void xValue(SqlFunction.Arguments args);
}
@@ -63,6 +63,7 @@ _sqlite3_file_control
_sqlite3_finalize
_sqlite3_free
_sqlite3_get_auxdata
_sqlite3_get_autocommit
_sqlite3_initialize
_sqlite3_keyword_count
_sqlite3_keyword_name
+1
View File
@@ -188,6 +188,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
["sqlite3_file_control", "int", "sqlite3*", "string", "int", "*"],
["sqlite3_finalize", "int", "sqlite3_stmt*"],
["sqlite3_free", undefined,"*"],
["sqlite3_get_autocommit", "int", "sqlite3*"],
["sqlite3_get_auxdata", "*", "sqlite3_context*", "int"],
["sqlite3_initialize", undefined],
/*["sqlite3_interrupt", undefined, "sqlite3*"
+32 -1
View File
@@ -62,7 +62,7 @@
```
{
type: string, // one of: 'open', 'close', 'exec', 'config-get'
type: string, // one of: 'open', 'close', 'exec', 'export', 'config-get'
messageId: OPTIONAL arbitrary value. The worker will copy it as-is
into response messages to assist in client-side dispatching.
@@ -325,6 +325,37 @@
passed only a string), noting that options.resultRows and
options.columnNames may be populated by the call to db.exec().
====================================================================
"export" the current db
To export the underlying database as a byte array...
Message format:
```
{
type: "export",
messageId: ...as above...,
dbId: ...as above...
}
```
Response:
```
{
type: "export",
messageId: ...as above...,
dbId: ...as above...
result: {
byteArray: Uint8Array (as per sqlite3_js_db_export()),
filename: the db filename,
mimetype: "application/x-sqlite3"
}
}
```
*/
globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
sqlite3.initWorker1API = function(){
+1 -1
View File
@@ -22,7 +22,7 @@ const tryOpfsVfs = async function(sqlite3){
const opfs = sqlite3.opfs;
log("tryOpfsVfs()");
if(!sqlite3.opfs){
const e = toss("OPFS is not available.");
const e = new Error("OPFS is not available.");
error(e);
throw e;
}
+6 -24
View File
@@ -1688,7 +1688,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
wasm.sqlite3_wasm_vfs_unlink(0, filename);
}
}
}/*sqlite3_js_vfs_create_file()*/)
}/*sqlite3_js_posix_create_file()*/)
////////////////////////////////////////////////////////////////////
.t({
@@ -2605,28 +2605,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
}
}
}/*kvvfs sanity checks*/)
.t({
name: 'kvvfs sqlite3_js_vfs_create_file()',
predicate: ()=>"kvvfs does not currently support this",
test: function(sqlite3){
let db;
try {
db = new this.JDb(this.kvvfsDbFile);
const exp = capi.sqlite3_js_db_export(db);
db.close();
this.kvvfsUnlink();
capi.sqlite3_js_vfs_create_file("kvvfs", this.kvvfsDbFile, exp);
db = new this.JDb(filename);
T.assert(6 === db.selectValue('select count(*) from kvvfs'));
}finally{
db.close();
this.kvvfsUnlink();
}
delete this.kvvfsDbFile;
delete this.kvvfsUnlink;
delete this.JDb;
}
}/*kvvfs sqlite3_js_vfs_create_file()*/)
;/* end kvvfs tests */
////////////////////////////////////////////////////////////////////////
@@ -2644,13 +2622,17 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
T.assert( 0 === rc /*void pointer*/ );
// Commit hook...
T.assert( 0!=capi.sqlite3_get_autocommit(db) );
db.exec("BEGIN; SELECT 1; COMMIT");
T.assert(0 === countCommit,
"No-op transactions (mostly) do not trigger commit hook.");
db.exec("BEGIN EXCLUSIVE; SELECT 1; COMMIT");
T.assert(1 === countCommit,
"But EXCLUSIVE transactions do.");
db.transaction((d)=>{d.exec("create table t(a)");});
db.transaction((d)=>{
T.assert( 0==capi.sqlite3_get_autocommit(db) );
d.exec("create table t(a)");
});
T.assert(2 === countCommit);
// Rollback hook:
+89 -88
View File
@@ -1,13 +1,13 @@
C Version\s3.44.2
D 2023-11-24T11:41:44.921
C Use\sextra\sassert()\sstatement\sto\ssilence\sharmless\sstatic\sanalyzer\swarnings.
D 2023-12-05T19:24:07.192
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in bddd493839ce057414b19cd405293363f7efb7a73a3d8f6d2ed1b59943ddfcb1
F Makefile.in 890caf094636c308bc981032baf8f9208bf307755f9197ae4218a9fbcec2e449
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
F Makefile.msc 59bb36dba001f0b38212be0794fb838f25371008b180929bcf08aa799694c168
F README.md 963d30019abf0cc06b263cd2824bce022893f3f93a531758f6f04ff2194a16a8
F VERSION 672a5ddf487d19856d8b1015797e14578fd8f8d59c14d9832ab0fe5938c6ab9b
F VERSION 73573d4545343f001bf5dc5461173a7c78c203dd046cabcf99153878cf25d3a6
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
@@ -22,7 +22,7 @@ F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d
F autoconf/tea/Makefile.in 106a96f2f745d41a0f6193f1de98d7355830b65d45032c18cd7c90295ec24196
F autoconf/tea/README 3e9a3c060f29a44344ab50aec506f4db903fb873
F autoconf/tea/aclocal.m4 52c47aac44ce0ddb1f918b6993e8beb8eee88f43
F autoconf/tea/configure.ac 0c358d924fe9cd5c624b9038e025bca35b572a15501014c69afe38b8ae4d7371
F autoconf/tea/configure.ac 4c32b08691a5b296206b38422b53b92b65be3d3f6b3dd6552a50981a61f5acda
F autoconf/tea/doc/sqlite3.n e1fe45d4f5286ee3d0ccc877aca2a0def488e9bb
F autoconf/tea/license.terms 13bd403c9610fd2b76ece0ab50c4c5eda933d523
F autoconf/tea/pkgIndex.tcl.in b9eb6dd37f64e08e637d576b3c83259814b9cddd78bec4af2e5abfc6c5c750ce
@@ -33,15 +33,15 @@ F autoconf/tea/win/nmakehlp.c b01f822eabbe1ed2b64e70882d97d48402b42d2689a1ea0034
F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
F config.guess 883205ddf25b46f10c181818bf42c09da9888884af96f79e1719264345053bd6
F config.sub c2d0260f17f3e4bc0b6808fccf1b291cb5e9126c14fc5890efc77b9fd0175559
F configure a56c8f24e118eff90e3870411bfc844e86c00577faf092ded131120a637ad2da x
F configure.ac de31fea7d975bb7ebafbe0e2190a855cc80d48558bf0c9a6578a1836daf1cd3a
F configure bcb1042e92775424a1021d2f4c89c78a699a6225df01fa8c593df7df0be6ad10 x
F configure.ac f25bd7843120f2c2b8bc9db5a92b0502bbdd28e68907415c3d42fc8e57c657b9
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/F2FS.txt c1d4a0ae9711cfe0e1d8b019d154f1c29e0d3abfe820787ba1e9ed7691160fcd
F doc/compile-for-windows.md 922ba580d210a1f1bd3ef9d0413121556f9b5714fb5c01e664d980f85fa4ac8c
F doc/compile-for-windows.md 50b27d77be96195c66031a3181cb8684ed822327ea834e07f9c014213e5e3bcf
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/lemon.html 44a53a1d2b42d7751f7b2f478efb23c978e258d794bfd172442307a755b9fa44
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/testrunner.md 2434864be2219d4f0b6ffc99d0a2172d531c4ca4345340776f67ad4edd90dc90
F doc/testrunner.md 8d36ec692cf4994bb66d84a4645b9afa1ce9d47dc12cbf8d437c5a5fb6ddeedb
F doc/trusted-schema.md 33625008620e879c7bcfbbfa079587612c434fa094d338b08242288d358c3e8a
F doc/vdbesort-memory.md 4da2639c14cd24a31e0af694b1a8dd37eaf277aff3867e9a8cc14046bc49df56
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
@@ -50,8 +50,8 @@ F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
F ext/async/sqlite3async.c 6f247666b495c477628dd19364d279c78ea48cd90c72d9f9b98ad1aff3294f94
F ext/async/sqlite3async.h 46b47c79357b97ad85d20d2795942c0020dc20c532114a49808287f04aa5309a
F ext/consio/console_io.c e048bd69f3a357a4b6b5da01c504728631d944ad5735ad83c44800c80a91e978 x
F ext/consio/console_io.h d18bcc50f4e4d42b65be8fecba72918364ae77182c86360aca842e44b823384e
F ext/consio/console_io.c 097323f60037d70523421f0248958d2280851f8ff2f9a443d4ee1474c4769118 x
F ext/consio/console_io.h 3228dff1717481202a24f6dcf45ce0b75e7a778bf6877089518a44e1473b76a3
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 0dd5cb096d66bed593e33053a3b364f6ef52ed72064bf5cf298364636dbf3cd6
@@ -91,7 +91,7 @@ F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a0
F ext/fts5/extract_api_docs.tcl a36e54ec777172ddd3f9a88daf593b00848368e0
F ext/fts5/fts5.h 05501612cc655504c5dce8ba765ab621d50fc478490089beaa0d75e00b23e520
F ext/fts5/fts5Int.h 78a63cc0795186cde5384816a9403a68c65774b35d952e05b81a1b4b158e07c8
F ext/fts5/fts5_aux.c 35c4101613eff86902877a4dedd9400b07922e412cbdd637b45041dce2fd5388
F ext/fts5/fts5_aux.c ee770eec0af8646db9e18fc01a0dad7345b5f5e8cbba236704cfae2d777022ad
F ext/fts5/fts5_buffer.c 3001fbabb585d6de52947b44b455235072b741038391f830d6b729225eeaf6a5
F ext/fts5/fts5_config.c 054359543566cbff1ba65a188330660a5457299513ac71c53b3a07d934c7b081
F ext/fts5/fts5_expr.c bd3b81ce669c4104e34ffe66570af1999a317b142c15fccb112de9fb0caa57a6
@@ -102,7 +102,7 @@ F ext/fts5/fts5_storage.c 5d10b9bdcce5b90656cad13c7d12ad4148677d4b9e3fca0481fca5
F ext/fts5/fts5_tcl.c b1445cbe69908c411df8084a10b2485500ac70a9c747cdc8cda175a3da59d8ae
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
F ext/fts5/fts5_tokenize.c 5e251efb0f1af99a25ed50010ba6b1ad1250aca5921af1988fdcabe5ebc3cb43
F ext/fts5/fts5_tokenize.c 83cfcede3898001cab84432a36ce1503e3080cf9b1c682b022ec82e267ea4c13
F ext/fts5/fts5_unicode2.c eca63dbc797f8ff0572e97caf4631389c0ab900d6364861b915bdd4735973f00
F ext/fts5/fts5_varint.c e64d2113f6e1bfee0032972cffc1207b77af63319746951bf1d09885d1dadf80
F ext/fts5/fts5_vocab.c aed56169ae5c1aa9b8189c779ffeef04ed516d3c712c06914e6d91a6759f4e4a
@@ -219,7 +219,9 @@ F ext/fts5/test/fts5synonym2.test 8f891fc49cc1e8daed727051e77e1f42849c784a6a54be
F ext/fts5/test/fts5tok1.test 1f7817499f5971450d8c4a652114b3d833393c8134e32422d0af27884ffe9cef
F ext/fts5/test/fts5tok2.test dcacb32d4a2a3f0dd3215d4a3987f78ae4be21a2
F ext/fts5/test/fts5tokenizer.test ac3c9112b263a639fb0508ae73a3ee886bf4866d2153771a8e8a20c721305a43
F ext/fts5/test/fts5tokenizer2.test cb5428c7cfb3b6a74b7adfcde65506e329112003e8dffa7501d01c2d18d02569
F ext/fts5/test/fts5trigram.test 6c4e37864f3e7d90673db5563d9736d7e40080ab94d10ebdffa94c1b77941da0
F ext/fts5/test/fts5trigram2.test 9fe4207f8a4241747aff1005258b564958588d21bfd240d6cd4c2e955d31c156
F ext/fts5/test/fts5ubsan.test 783d5a8d13ebfa169e634940228db54540780e3ba7a87ad1e4510e61440bf64b
F ext/fts5/test/fts5umlaut.test a42fe2fe6387c40c49ab27ccbd070e1ae38e07f38d05926482cc0bccac9ad602
F ext/fts5/test/fts5unicode.test 17056f4efe6b0a5d4f41fdf7a7dc9af2873004562eaa899d40633b93dc95f5a9
@@ -239,49 +241,50 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
F ext/jni/GNUmakefile 5c3ac326bf3853486ebe0d70819abc790cc65c412182ce4ebd5012b008d9b059
F ext/jni/README.md ef9ac115e97704ea995d743b4a8334e23c659e5534c3b64065a5405256d5f2f4
F ext/jni/GNUmakefile 59eb05f2a363bdfac8d15d66bed624bfe1ff289229184f3861b95f98a19cf4b2
F ext/jni/README.md d899789a9082a07b99bf30b1bbb6204ae57c060efcaa634536fa669323918f42
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c 6f6df9657989e9ca2cfdcc2fe9a71c279de56d5c941adfd09a0f24256de35c8f
F ext/jni/src/c/sqlite3-jni.h b4c413a0d0c734683da1049cfcf89e35ae2719759d0656ec0f8c57188f18cab8
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java a99341e88154e70447596b1af6a27c586317df41a7e0f246fd41370cd7b723b2
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 0b1879852707f752512d4db9d7edd0d8db2f0c2612316ce1c832715e012ff6ba
F ext/jni/src/c/sqlite3-jni.c 6040c0de97644a1fb14bb589ee9f2f4208f6e6b165d14a0e33ed24945b118838
F ext/jni/src/c/sqlite3-jni.h 913ab8e8fee432ae40f0e387c8231118d17053714703f5ded18202912a8a3fbf
F ext/jni/src/org/sqlite/jni/annotation/Experimental.java 8603498634e41d0f7c70f661f64e05df64376562ea8f126829fd1e0cdd47e82b
F ext/jni/src/org/sqlite/jni/annotation/NotNull.java 38e7e58a69b26dc100e458b31dfa3b2a7d67bc36d051325526ef1987d5bc8a24
F ext/jni/src/org/sqlite/jni/annotation/Nullable.java 56e3dee1f3f703a545dfdeddc1c3d64d1581172b1ad01ffcae95c18547fafd90
F ext/jni/src/org/sqlite/jni/annotation/package-info.java 977b374aed9d5853cbf3438ba3b0940abfa2ea4574f702a2448ee143b98ac3ca
F ext/jni/src/org/sqlite/jni/capi/AbstractCollationCallback.java 1afa90d3f236f79cc7fcd2497e111992644f7596fbc8e8bcf7f1908ae00acd6c
F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java bc29e986c866c2ddbbb9f935f5b7264c1c1026864e50a4a735192864f75e37c0
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java 7ed409d5449684616cc924534e22ff6b07d361f12ad904b69ecb10e0568a8013
F ext/jni/src/org/sqlite/jni/capi/AggregateFunction.java 0b72cdff61533b564d65b63418129656daa9a9f30e7e7be982bd5ab394b1dbd0
F ext/jni/src/org/sqlite/jni/capi/AuthorizerCallback.java c045a5b47e02bb5f1af91973814a905f12048c428a3504fbc5266d1c1be3de5a
F ext/jni/src/org/sqlite/jni/capi/AutoExtensionCallback.java 74cc4998a73d6563542ecb90804a3c4f4e828cb4bd69e61226d1a51f4646e759
F ext/jni/src/org/sqlite/jni/capi/BusyHandlerCallback.java 7b8e19810c42b0ad21a04b5d8c804b32ee5905d137148703f16a75b612c380ca
F ext/jni/src/org/sqlite/jni/capi/CApi.java bccb442ca81cd4decb1adae99006a60b7a9f54e5153842e738c01104e97d1de0
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 0bfd6e56e8265c2f05c9207665707285534d78f8466ef0e0430c65677f00943d
F ext/jni/src/org/sqlite/jni/capi/CApi.java d428a1fd3b827f01c55d10d21ff35e33e7dac9e8a1d92a8b5c7d7255e67407d8
F ext/jni/src/org/sqlite/jni/capi/CallbackProxy.java 57e2d275dcebe690b1fc1f3d34eb96879b2d7039bce30b563aee547bf45d8a8b
F ext/jni/src/org/sqlite/jni/capi/CollationCallback.java e29bcfc540fdd343e2f5cca4d27235113f2886acb13380686756d5cabdfd065a
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java f81cf10b79c52f9b2e9247d523d29ae48863935f60420eae35f257c38c80ce95
F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 29c002f3c638cc80f7db1594564a262d1beb32637824c3dca2d60a224d1f71d7
F ext/jni/src/org/sqlite/jni/capi/CollationNeededCallback.java 5bfa226a8e7a92e804fd52d6e42b4c7b875fa7a94f8e2c330af8cc244a8920ab
F ext/jni/src/org/sqlite/jni/capi/CommitHookCallback.java 482f53dfec9e3ac2a9070d3fceebd56250932aaaf7c4f5bc8de29fc011416e0c
F ext/jni/src/org/sqlite/jni/capi/ConfigLogCallback.java b995ca412f59b631803b93aa5b3684fce62e335d1e123207084c054abfd488d4
F ext/jni/src/org/sqlite/jni/capi/ConfigSqllogCallback.java 701f2e4d8bdeb27cfbeeb56315d15b13d8752b0fdbca705f31bd4366c58d8a33
F ext/jni/src/org/sqlite/jni/capi/ConfigSqlLogCallback.java e5723900b6458bc6288f52187090a78ebe0a20f403ac7c887ec9061dfe51aba7
F ext/jni/src/org/sqlite/jni/capi/NativePointerHolder.java b7036dcb1ef1b39f1f36ac605dde0ff1a24a9a01ade6aa1a605039443e089a61
F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 68f60aec7aeb5cd4e5fb83449037f668c63cb99f682ee1036cc226d0cbd909b9
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java aca8f9fa72e3b6602bc9a7dd3ae9f5b2808103fbbee9b2749dc96c19cdc261a1
F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java 819d938e26208adde17ca4b7ddde1d8cd6915b6ab7b708249a9787beca6bd6b6
F ext/jni/src/org/sqlite/jni/capi/OutputPointer.java 246b0e66c4603f41c567105a21189d138aaf8c58203ecd4928802333da553e7c
F ext/jni/src/org/sqlite/jni/capi/PrepareMultiCallback.java 97352091abd7556167f4799076396279a51749fdae2b72a6ba61cd39b3df0359
F ext/jni/src/org/sqlite/jni/capi/PreupdateHookCallback.java efcf57545c5e282d1dd332fa63329b3b218d98f356ef107a9dbe3979be82213a
F ext/jni/src/org/sqlite/jni/capi/ProgressHandlerCallback.java 01bc0c238eed2d5f93c73522cb7849a445cc9098c2ed1e78248fa20ed1cfde5b
F ext/jni/src/org/sqlite/jni/capi/ResultCode.java 8141171f1bcf9f46eef303b9d3c5dc2537a25ad1628f3638398d8a60cacefa7f
F ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java 105e324d09c207100485e7667ad172e64322c62426bb49b547e9b0dc9c33f5f0
F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java fef556adbc3624292423083a648bdf97fa8a4f6b3b6577c9660dd7bd6a6d3c4a
F ext/jni/src/org/sqlite/jni/capi/RollbackHookCallback.java e172210a2080e851ebb694c70e9f0bf89284237795e38710a7f5f1b61e3f6787
F ext/jni/src/org/sqlite/jni/capi/SQLFunction.java 0d1e9afc9ff8a2adb94a155b72385155fa3b8011a5cca0bb3c28468c7131c1a5
F ext/jni/src/org/sqlite/jni/capi/SQLTester.java 09bee15aa0eedac68d767ae21d9a6a62a31ade59182a3ccbf036d6463d9e30b1
F ext/jni/src/org/sqlite/jni/capi/ScalarFunction.java 93b9700fca4c68075ccab12fe0fbbc76c91cafc9f368e835b9bd7cd7732c8615
F ext/jni/src/org/sqlite/jni/capi/TableColumnMetadata.java addf120e0e76e5be1ff2260daa7ce305ff9b5fafd64153a7a28e9d8f000a815f
F ext/jni/src/org/sqlite/jni/capi/Tester1.java ca195521b6bda3e0cd00e76bb71ec8060d1fab76a2f13b1af9feea40789f44bb
F ext/jni/src/org/sqlite/jni/capi/Tester1.java e5fa17301b7266c1cbe4bcce67788e08e45871c7c72c153d515abb37e501de0a
F ext/jni/src/org/sqlite/jni/capi/TraceV2Callback.java 0a25e117a0daae3394a77f24713e36d7b44c67d6e6d30e9e1d56a63442eef723
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java 2766b8526bbffc4f1045f70e79f1bc1b1efe1c3e95ca06cdb8a7391032dda3b4
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 9f9e151f1da017b706c0ee5f40f4c86b54e773d6ae4339723e0cc85a456251ab
F ext/jni/src/org/sqlite/jni/capi/UpdateHookCallback.java c8bdf7848e6599115d601bcc9427ff902cb33129b9be32870ac6808e04b6ae56
F ext/jni/src/org/sqlite/jni/capi/ValueHolder.java 2ce069f3e007fdbbe1f4e507a5a407fc9679da31a0aa40985e6317ed4d5ec7b5
F ext/jni/src/org/sqlite/jni/capi/WindowFunction.java caf4396f91b2567904cf94bc538a069fd62260d975bd037d15a02a890ed1ef9e
F ext/jni/src/org/sqlite/jni/capi/XDestroyCallback.java f3abb8dd7381f53ebba909437090caf68200f06717b8a7d6aa96fa3e8133117d
F ext/jni/src/org/sqlite/jni/capi/package-info.java 08ff986a65d2be9162442c82d28a65ce431d826f188520717c2ecb1484d0a50e
F ext/jni/src/org/sqlite/jni/capi/sqlite3.java 4010bbebc5bf44e2044e610786088cdee7dc155da2b333c0551492ff1cedf33b
F ext/jni/src/org/sqlite/jni/capi/sqlite3.java c6a5c555d163d76663534f2b2cce7cab15325b9852d0f58c6688a85e73ae52f0
F ext/jni/src/org/sqlite/jni/capi/sqlite3_backup.java 6742b431cd4d77e8000c1f92ec66265a58414c86bf3b0b5fbcb1164e08477227
F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java f204ab6ab1263e119fe43730141a00662d80972129a5351dfb11aae5d282df36
F ext/jni/src/org/sqlite/jni/capi/sqlite3_blob.java 59e26ca5254cd4771f467237bcfe2d8deed30a77152fabcd4574fd406c301d63
F ext/jni/src/org/sqlite/jni/capi/sqlite3_context.java f0ef982009c335c4393ffcb68051809ca1711e4f47bcb8d1d46952f22c01bc22
F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java ff579621e9bd5ffbc6b2ef9f996c12db4df6e0c8cc5697c91273e5fca279fcf8
F ext/jni/src/org/sqlite/jni/capi/sqlite3_stmt.java 293b5fa7d5b5724c87de544654aca1103d76f3092bc2c8f4360102a65ba25dff
F ext/jni/src/org/sqlite/jni/capi/sqlite3_value.java e1d62a257c13504b46d39d5c21c49cf157ad73fda00cc5f34c931aa008c37049
F ext/jni/src/org/sqlite/jni/fts5/Fts5.java e94681023785f1eff5399f0ddc82f46b035977d350f14838db659236ebdf6b41
F ext/jni/src/org/sqlite/jni/fts5/Fts5Context.java 338637e6e5a2cc385d962b220f3c1f475cc371d12ae43d18ef27327b6e6225f7
@@ -294,13 +297,14 @@ F ext/jni/src/org/sqlite/jni/fts5/fts5_api.java a8e88c3783d21cec51b0748568a96653
F ext/jni/src/org/sqlite/jni/fts5/fts5_extension_function.java 9e2b954d210d572552b28aca523b272fae14bd41e318921b22f65b728d5bf978
F ext/jni/src/org/sqlite/jni/fts5/fts5_tokenizer.java 92bdaa3893bd684533004d64ade23d329843f809cd0d0f4f1a2856da6e6b4d90
F ext/jni/src/org/sqlite/jni/test-script-interpreter.md f9f25126127045d051e918fe59004a1485311c50a13edbf18c79a6ff9160030e
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java 5ad99bd74c85f56bbef324d9ec29b4048f4620547c9a80093d8586c3557f9f9a
F ext/jni/src/org/sqlite/jni/wrapper1/AggregateFunction.java d5c108b02afd3c63c9e5e53f71f85273c1bfdc461ae526e0a0bb2b25e4df6483
F ext/jni/src/org/sqlite/jni/wrapper1/ScalarFunction.java 43c43adfb7866098aadaaca1620028a6ec82d5193149970019b1cce9eb59fb03
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 004394eeb944baa56e36cd7ae69ba6d4a52b52db3c49439db16e98270b861421
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java a9ddc6a9e8c113168cc67592ae24c0e56d30dd06226eeab012f2761a0889d7bb
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 1386f7b753134fc12253ce2fbbc448ba8c970567fac01a3356cb672e14408d73
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java c24b510ebe801c30533cc62efdf69a4a5e2da9ec4b49f8d403f2060693f060a0
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java 7b89a7391f771692c5b83b0a5b86266abe8d59f1c77d7a0eccc9b79f259d79af
F ext/jni/src/org/sqlite/jni/wrapper1/SqlFunction.java 27b141f5914c7cb0e40e90a301d5e05b77f3bd42236834a68031b7086381fafd
F ext/jni/src/org/sqlite/jni/wrapper1/Sqlite.java ada39f18e4e3e9d4868dadbc3f7bfe1c6c7fde74fb1fb2954c3f0f70120b805c
F ext/jni/src/org/sqlite/jni/wrapper1/SqliteException.java 982538ddb4c0719ef87dfa664cd137b09890b546029a7477810bd64d4c47ee35
F ext/jni/src/org/sqlite/jni/wrapper1/Tester2.java ce45f2ec85facbb73690096547ed166e7be82299e3d92eaa206f82b60a6ec969
F ext/jni/src/org/sqlite/jni/wrapper1/ValueHolder.java a84e90c43724a69c2ecebd601bc8e5139f869b7d08cb705c77ef757dacdd0593
F ext/jni/src/org/sqlite/jni/wrapper1/WindowFunction.java c7d1452f9ff26175b3c19bbf273116cc2846610af68e01756d755f037fe7319f
F ext/jni/src/tests/000-000-sanity.test c3427a0e0ac84d7cbe4c95fdc1cd4b61f9ddcf43443408f3000139478c4dc745
F ext/jni/src/tests/000-001-ignored.test e17e874c6ab3c437f1293d88093cf06286083b65bf162317f91bbfd92f961b70
F ext/jni/src/tests/900-001-fts.test bf0ce17a8d082773450e91f2388f5bbb2dfa316d0b676c313c637a91198090f0
@@ -572,7 +576,7 @@ F ext/wasm/SQLTester/SQLTester.mjs ec2f6ba63a0f2f0562941a0fb8e46b7dc55589711513f
F ext/wasm/SQLTester/SQLTester.run.mjs c72b7fe2072d05992f7a3d8c6a1d34e95712513ceabe40849784e24e41c84638
F ext/wasm/SQLTester/index.html 3f8a016df0776be76605abf20e815ecaafbe055abac0e1fe5ea080e7846b760d
F ext/wasm/SQLTester/touint8array.c 2d5ece04ec1393a6a60c4bf96385bda5e1a10ad49f3038b96460fc5e5aa7e536
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api f442460ed9a109e637dd3ea1caa4489553ad9414e8988118b208bb7a4bbece6b
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-see fb29e62082a658f0d81102488414d422c393c4b20cc2f685b216bc566237957b
F ext/wasm/api/EXPORTED_RUNTIME_METHODS.sqlite3-api 1ec3c73e7d66e95529c3c64ac3de2470b0e9e7fbf7a5b41261c367cf4f1b7287
F ext/wasm/api/README.md 5eb44fa02e9c693a1884a3692428647894b0380b24bca120866b7a24c8786134
@@ -582,10 +586,10 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08
F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
F ext/wasm/api/sqlite3-api-glue.js 26aedfb27915f4f316f6eac84078443e4f0d2dfe5f012310014923ed4b77b2b6
F ext/wasm/api/sqlite3-api-glue.js 119b91c8a7ce6648679eb66fcdd1ed07ef7fd892eb501d658fbfefcc962012d9
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
F ext/wasm/api/sqlite3-api-prologue.js 9aeba7b45cf41b3a26d34d7fb2525633cd1adfc544888c1ea8dbb077496f4ce9
F ext/wasm/api/sqlite3-api-worker1.js f941382f21006b4a817754184e2661b0a63ce650201f3419cd60f4758b6fd60e
F ext/wasm/api/sqlite3-api-worker1.js 88770ac01fc756f89a3e060eec17111d6c1688e89ebfd34cb9d9e54d25affbb9
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
@@ -633,10 +637,10 @@ F ext/wasm/split-speedtest1-script.sh a3e271938d4d14ee49105eb05567c6a69ba4c1f129
F ext/wasm/sql/000-mandelbrot.sql 775337a4b80938ac8146aedf88808282f04d02d983d82675bd63d9c2d97a15f0
F ext/wasm/sql/001-sudoku.sql 35b7cb7239ba5d5f193bc05ec379bcf66891bce6f2a5b3879f2f78d0917299b5
F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555e685bce3da8c3f
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
F ext/wasm/test-opfs-vfs.js 1618670e466f424aa289859fe0ec8ded223e42e9e69b5c851f809baaaca1a00c
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
F ext/wasm/tester1.c-pp.js fb20d9e1c308ea34a29d8afdda1a6c5edc406241b5560fa23c19c14747ee41bc
F ext/wasm/tester1.c-pp.js a92dc256738dbd1b50f142d1fd0c835294ba09b7bb6526650360e942f88cb63f
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
@@ -665,16 +669,16 @@ F src/bitvec.c 9eac5f42c11914d5ef00a75605bb205e934f435c579687f985f1f8b0995c8645
F src/btmutex.c 79a43670447eacc651519a429f6ece9fd638563cf95b469d6891185ddae2b522
F src/btree.c f3b09c5414de3a11db73e11e1d66f4c5e53c9e89876ff3b531a887ab656ca303 x
F src/btree.h 03e3356f5208bcab8eed4e094240fdac4a7f9f5ddf5e91045ce589f67d47c240
F src/btreeInt.h ef12a72b708677e48d6bc8dcd66fed25434740568b89e2cfa368093cfc5b9d15
F src/btreeInt.h 3e2589726c4f105e653461814f65857465da68be1fac688de340c43b873f4062
F src/build.c 189e4517d67f09f0a3e0d8e1faa6e2ef0c2e95f6ac82e33c912cb7efa2a359cc
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 23331529e654be40ca97d171cbbffe9b3d4c71cc53b78fe5501230675952da8b
F src/date.c eebc54a00e888d3c56147779e9f361b77d62fd69ff2008c5373946aa1ba1d574
F src/date.c 3b8d02977d160e128469de38493b4085f7c5cf4073193459909a6af3cf6d7c91
F src/dbpage.c 80e46e1df623ec40486da7a5086cb723b0275a6e2a7b01d9f9b5da0f04ba2782
F src/dbstat.c 3b677254d512fcafd4d0b341bf267b38b235ccfddbef24f9154e19360fa22e43
F src/delete.c cb766727c78e715f9fb7ec8a7d03658ed2a3016343ca687acfcec9083cdca500
F src/expr.c cacf230b124891ea830d80395ea2119c2d7ee52c134a010f3950de9391ab79d1
F src/expr.c e9a491c7f156e5b25641c28af11b735a424e108a21b9f83b6f3e51c99a8141d9
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c a47610f0a5c6cb0ad79f8fcef039c01833dec0c751bb695f28dc0ec6a4c3ba00
F src/func.c 472f6dcfa39cf54f89a6aec76c79c225fb880a6c14469c15d361331662b9bf43
@@ -684,7 +688,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
F src/json.c b2045aafc52f0475dc5d723d11cc0aaa9e1d233a28031b08c8174a3e407ed50c
F src/json.c 0a6095d10a8c8251e1838a1f12abc89125b0b05f82497ad12896a7f714e397ce
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
@@ -708,7 +712,7 @@ F src/os.h 1ff5ae51d339d0e30d8a9d814f4b8f8e448169304d83a7ed9db66a65732f3e63
F src/os_common.h 6c0eb8dd40ef3e12fe585a13e709710267a258e2c8dd1c40b1948a1d14582e06
F src/os_kv.c 4d39e1f1c180b11162c6dc4aa8ad34053873a639bac6baae23272fc03349986a
F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d872107
F src/os_unix.c cb116fde9e3ca3c1bbfdf89d6928f776a2a34da168e2667426523a4db353b271
F src/os_unix.c 97bdcd43315da7aaec9fea2da1ff7c9de458f93dd363e073f2742403a7f2e011
F src/os_win.c 4a50a154aeebc66a1f8fb79c1ff6dd5fe3d005556533361e0d460d41cb6a45a8
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 987ab3a2cd9065d62e9955474470ff733445e2357432a67e3d0f5a8f9313e334
@@ -717,19 +721,19 @@ F src/parse.y 020d80386eb216ec9520549106353c517d2bbc89be28752ffdca649a9eaf56ec
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
F src/pragma.c b3b4ad9c0298d63098a067acca613c21a5f56b4d176d5842922bcd0b07b7164e
F src/pragma.c b5b4cff830575e6188cd56a295a57448d2b9dbc53f0dae58e22b97354cda3781
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c bde74add20fc0e8ce0c4e937a1f70a36d17413afe4f71d3e103f5cb74b17c8d9
F src/printf.c 9da63b9ae1c14789bcae12840f5d800fd9302500cd2d62733fac77f0041b4750
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F src/resolve.c 31229276a8eb5b5de1428cd2d80f6f1cf8ffc5248be25e47cf575df12f1b8f23
F src/resolve.c d017bad7ba8e778617701a0e986fdeb393d67d6afa84fb28ef4e8b8ad2acf916
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c 85857bedd2913d888aa571755b48c54cd2e6e7fcb0087e19b226ee0368cfda1e
F src/shell.c.in cbe850737d4166347bfe5fc7d695229379347509bf114cf6abeb1e384f2d7a70
F src/sqlite.h.in 4f841d3d117b830ee5ee45e8d89ceff1195f3ebb72d041ace8d116ba4c103b35
F src/shell.c.in 7bb83293775e1a5586d65212997442bc7acc70a2f1b781745da64ec3c2e4ea97
F src/sqlite.h.in d93a4821d2f792467a60f7dc81268d1bb8634f40c31694ef254cab4f9921f96a
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
F src/sqliteInt.h 08efc0ad9ddbbc5ea859111521dff2c4cecc589c0c9a3e4840c927663b31445b
F src/sqliteInt.h aab66d149269f15f6f1011081b389f001f00b84045c69a4f9ec96dd68cc3a7d7
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -787,18 +791,18 @@ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
F src/treeview.c 62fafcd31eea60b718f8daf448116b7b19f90134ebc6c20777ddbb07f56a3d28
F src/treeview.c c6fc972683fd00f975d8b32a81c1f25d2fb7d4035366bf45c9f5622d3ccd70ee
F src/trigger.c 0905b96b04bb6658509f711a8207287f1315cdbc3df1a1b13ba6483c8e341c81
F src/update.c 6904814dd62a7a93bbb86d9f1419c7f134a9119582645854ab02b36b676d9f92
F src/upsert.c fa125a8d3410ce9a97b02cb50f7ae68a2476c405c76aa692d3acf6b8586e9242
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
F src/util.c b22cc9f203a8c0b9ee5338a67f8860347d14845864c10248bebe84518a781677
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
F src/vdbe.c 1cfb61c58193dcb74e8e0f90dc1405ff7fe39f43a1e9bdd38329e174f2102ed4
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
F src/vdbe.c f73bead140670fac1aa4227188827ada52387a5fe0ccff0dd5af2a906754d904
F src/vdbe.h 88e19a982df9027ec1c177c793d1a5d34dc23d8f06e3b2d997f43688b05ee0eb
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
F src/vdbeapi.c dd812ddd2f7806519e9d492c820456f86628bb6014b559034506e7f9d7f683c5
F src/vdbeaux.c 16f27624831aa6663fe5927b647a0a54dfda0088da9b170ebc14bce98c5ac414
F src/vdbeapi.c 8f57d60c89da0b60e6d4e272358c511f6bae4e24330bdb11f8b42f986d1bf21b
F src/vdbeaux.c c5a471b34e9c4cfc0295a3e10734fd197670ffaebcb742f284c8e17e8026ceea
F src/vdbeblob.c 13f9287b55b6356b4b1845410382d6bede203ceb29ef69388a4a3d007ffacbe5
F src/vdbemem.c 0012d5f01cc866833847c2f3ae4c318ac53a1cb3d28acad9c35e688039464cf0
F src/vdbesort.c 237840ca1947511fa59bd4e18b9eeae93f2af2468c34d2427b059f896230a547
@@ -806,10 +810,10 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8
F src/vdbevtab.c 2143db7db0ceed69b21422581f434baffc507a08d831565193a7a02882a1b6a7
F src/vtab.c 154725ebecd3bc02f7fbd7ad3974334f73fff76e02a964e828e48a7c5fb7efff
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 01e051a1e713d9eabdb25df38602837cec8f4c2cae448ce2cf6accc87af903e9
F src/wal.c e5247a3406531b705b44630e9ccf9ca0e5c74955ef19c06fbb146d765c500c20
F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
F src/where.c 45b2239e127beaaae2367e503ca4c82868d8fef707c7f7f4a6c0528e7d5f65ff
F src/where.c 1fdc69ce1333e9bd6d7d3df9fa5af1373a3f5bfdd52108d1dbc0ca85a55f777e
F src/whereInt.h 4b38c5889514e3aead3f27d0ee9a26e47c3f150efc59e2a8b4e3bc8835e4d7a1
F src/wherecode.c 5d77db30a2a3dd532492ae882de114edba2fae672622056b1c7fd61f5917a8f1
F src/whereexpr.c dc5096eca5ed503999be3bdee8a90c51361289a678d396a220912e9cb73b3c00
@@ -819,7 +823,7 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
F test/aggnested.test 2e738bfe2980df301a782f6e7bbf9459266f64f7e72f58f3b5c843bf897c568c
F test/aggnested.test ce85a6af7d59c3109e35c5f03b2cd11da1a9b1417371e2f942102d0f0d77fd62
F test/aggorderby.test e6b98dbbf3ababa96892435d387de2dcf602ef02c2b848d2d817473066f154ba
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
@@ -1016,7 +1020,7 @@ F test/ctime.test 340f362f41f92972bbd71f44e10569a5cc694062b692231bd08aa6fe6c1c47
F test/cursorhint.test 05cf0febe5c5f8a31f199401fd1c9322249e753950d55f26f9d5aca61408a270
F test/cursorhint2.test 6f3aa9cb19e7418967a10ec6905209bcbb5968054da855fc36c8beee9ae9c42f
F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68ccf2a7bb8
F test/date.test c0d17cdfd89395bc78087b131e3538d96f864b5029c335318011accc7c0d0934
F test/date.test ff2341a1ef71b9a27979494d299222f9a293aa22cb9ff6e9c38d88a895317ebf
F test/date2.test 7e12ec14aaf4d5e6294b4ba140445b0eca06ea50062a9c3a69c4ee13d0b6f8b1
F test/date3.test a1b77abf05c6772fe5ca2337cac1398892f2a41e62bce7e6be0f4a08a0e64ae5
F test/date4.test 8aeb3de5b5e9fda968baa9357e4c0fae573724b7904943410195a19e96e31b6a
@@ -1318,15 +1322,17 @@ F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd7
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json/README.md 63e3e589e1df8fd3cc1588ba1faaff659214003f8b77a15af5c6452b35e30ee2
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
F test/json/json-q1-b.txt 1e180fe6491efab307e318b22879e3a736ac9a96539bbde7911a13ee5b33abc7
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x
F test/json101.test bc05d2476fd6f7ead31ec05b43d1b24b2b193ae112fd8f0d2ed56d9a904f9fa5
F test/json102.test 4c69694773a470f1fda34e5f4ba24920b35184fb66050b450fc2ef9ab5ad310b
F test/json/json-speed-check.sh b060a9a6c696c0a807d8929400fa11bd7113edc58b0d66b9795f424f8d0db326 x
F test/json101.test 70587d7d35ef9e2126364ba70f0c951f70827cfbd28649d779ff3df7e8f87547
F test/json102.test 557a46e16df1aa9bdbc4076a71a45814ea0e7503d6621d87d42a8c04cbc2b0ef
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
F test/json105.test 11670a4387f4308ae0318cadcbd6a918ea7edcd19fbafde020720a073952675d
F test/json501.test c419deb835b70c1a2c8532936927bcc1146730328edd2052276715bfd209724d
F test/json105.test e64a8d73677fbae67886642cd5076e2ef3efe89f8483b87595cf9c030216c9bd
F test/json501.test ab168a12eb6eb14d479f8c1cdae3ac062fd5a4679f17f976e96f1af518408330
F test/json502.test 98c38e3c4573841028a1381dfb81d4c3f9b105d39668167da10d055e503f6d0b
F test/jsonb01.test cace70765b36a36aec9a85a41ea65667d3bbf647d4400ddc3ac76f8fe7d94f90
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
F test/kvtest.c 6e0228409ea7ca0497dad503fbd109badb5e59545d131014b6aaac68b56f484a
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
@@ -1487,7 +1493,6 @@ F test/recover.test fd5199f928757cb308661b5fdca1abc19398a798ff7f24b57c3071e9f8e0
F test/regexp1.test 8f2a8bc1569666e29a4cee6c1a666cd224eb6d50e2470d1dc1df995170f3e0f1
F test/regexp2.test 55ed41da802b0e284ac7e2fe944be3948f93ff25abbca0361a609acfed1368b5
F test/reindex.test cd9d6021729910ece82267b4f5e1b5ac2911a7566c43b43c176a6a4732e2118d
F test/releasetest_data.tcl 80ef3941bf7ad136f4dc3d8960786f10a4f488797238171bdd757cc6eb4c3efa
F test/resetdb.test 54c06f18bc832ac6d6319e5ab23d5c8dd49fdbeec7c696d791682a8006bd5fc3
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/returning1.test db532cde29d6aebbc48c6ddc3149b30476f8e69ca7a2c4b53986c7635e6fd8ec
@@ -1587,7 +1592,7 @@ F test/snapshot2.test 8d6ff5dd9cc503f6e12d408a30409c3f9c653507b24408d9cd7195931c
F test/snapshot3.test 8744313270c55f6e18574283553d3c5c5fe4c5970585663613a0e75c151e599b
F test/snapshot4.test d4e9347ef2fcabc491fc893506c7bbaf334da3be111d6eb4f3a97cc623b78322
F test/snapshot_fault.test 129234ceb9b26a0e1000e8563a16e790f5c1412354e70749cbd78c3d5d07d60a
F test/snapshot_up.test a0a29c4cf33475fcef07c3f8e64af795e24ab91b4cc68295863402a393cdd41c
F test/snapshot_up.test 77dc7853bfb2b4fa249f76e1714cfa1e596826165d9ef22c06ac3a0b7b778d9a
F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
F test/sort.test f86751134159abb5e5fd4381a0d7038c91013638cd1e3fa1d7850901f6df6196
@@ -1650,8 +1655,8 @@ F test/temptable2.test 76821347810ecc88203e6ef0dd6897b6036ac788e9dd3e6b04fd4d163
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 68454ef88508c196d19e8694daa27bff7107a91857799eaa12f417188ae53ede
F test/testrunner.tcl 14c8b8ece841b1dd17516a0dc9c7ad9b5f4d4db7987974d3fdf66ae56b2a71fa
F test/testrunner_data.tcl 7f73f93634d32dafc857ed491b840f371113d09fde6a8bfb9e47b938d47b8c85
F test/testrunner.tcl e18d71f2e797da808ba6d31335e504ed6b2791581b89287a72b697a2f31b1ea1
F test/testrunner_data.tcl e4d5017290a6d5c11785e36cc94c67d8bb950c8cdc2dbe4c1db2a3a583812560
F test/thread001.test a0985c117eab62c0c65526e9fa5d1360dd1cac5b03bde223902763274ce21899
F test/thread002.test c24c83408e35ba5a952a3638b7ac03ccdf1ce4409289c54a050ac4c5f1de7502
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1816,7 +1821,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpch01.test 4479008f85f6f8f25f7ab2cb305d665752b4727fa28a8df3d8e0ad46520c62ff
F test/trace.test a659a9862957f4789e37a92b3bf6d2caf5c86b02cdeefc41e850ae53acf6992a
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
F test/trace3.test ae2004df24b585fed9046cc0bae4601762bc6fc4aa321d475f1350bba5047f31
F test/trace3.test 4f418ed30d15d9d17dcf13a17f0bd99a92e3038e038798e35db7525f82f4c281
F test/trans.test 45f6f9ab6f66a7b5744f1caac06b558f95da62501916906cf55586a896f9f439
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
@@ -1952,8 +1957,6 @@ F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
F test/walvfs.test e1a6ad0f3c78e98b55c3d5f0889cf366cc0d0a1cb2bccb44ac9ec67384adc4a1
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl 1bea58a6a8e68a73f542ee4fca28b771b84ed803bd0c9e385087070b3d747b3c x
F test/where.test 59abb854eee24f166b5f7ba9d17eb250abc59ce0a66c48912ffb10763648196d
F test/where2.test 03c21a11e7b90e2845fc3c8b4002fc44cc2797fa74c86ee47d70bd7ea4f29ed6
F test/where3.test 5b4ffc0ac2ea0fe92f02b1244b7531522fe4d7bccf6fa8741d54e82c10e67753
@@ -1985,7 +1988,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test e0924eb8daac02bf80e9da88930747bd44dd9b230b7759fed927b1655b467c9c
F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test ccfeaf116afc6a8f748a8122a4f1ee6b69e6bbc5acee61197d3c17167338b100
F test/window1.test 5e8abe56a7d667eeddbba6de180086dcf69ed528d046447a25464f945ece101f
F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
@@ -2109,7 +2112,7 @@ F tool/sqltclsh.c.in 1bcc2e9da58fadf17b0bf6a50e68c1159e602ce057210b655d50bad5aaa
F tool/sqltclsh.tcl 862f4cf1418df5e1315b5db3b5ebe88969e2a784525af5fbf9596592f14ed848
F tool/src-verify.c 41c586dee84d0b190ad13e0282ed83d4a65ec9fefde9adf4943efdf6558eea7f
F tool/srcck1.c 371de5363b70154012955544f86fdee8f6e5326f
F tool/srctree-check.tcl 9f1098d439159692ece45cc9e701b35df4956269399fe0c770e41f235d1ce5e6
F tool/srctree-check.tcl c15f860a3c97d5f7b4c14b60392d9466af29dd006c4ef18127f502641e2977a8
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
F tool/stripccomments.c 20b8aabc4694d0d4af5566e42da1f1a03aff057689370326e9269a9ddcffdc37
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
@@ -2142,10 +2145,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P f796da626b5c3b099cc246a8b46d92839922e34f398d673b0b03d7ee33a28a60
R 1ffc537351df4c25512f7c1fd5cd9511
T +sym-release *
T +sym-version-3.44.2 *
P 59446dc0bd0091572122a3c8b4653d7a2dc867d16c4a5919f79b81bc3a673ce3
R 901a6c57f6544c02dc1f928ffbc0f678
U drh
Z abd52f0184ebdbba1837e841b542823e
Z d3a76b74f5e90cbdae4d0a0216cf9ffb
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
ebead0e7230cd33bcec9f95d2183069565b9e709bf745c9b5db65cc0cbf92c0f
174c2b2eef5fecd96a5fc89b81032fe81f7801f12097cea10e7e7f0a02114813
+1 -1
View File
@@ -64,7 +64,7 @@
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
** 28 4 Reserved for future use
** 28 4 The size of the database in pages
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
+6
View File
@@ -1043,6 +1043,12 @@ static int isDate(
}
computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1;
if( argc==1 && p->validYMD && p->D>28 ){
/* Make sure a YYYY-MM-DD is normalized.
** Example: 2023-02-31 -> 2023-03-03 */
assert( p->validJD );
p->validYMD = 0;
}
return 0;
}
+2 -1
View File
@@ -6769,13 +6769,14 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
&& pWalker->walkerDepth==pExpr->op2
&& pExpr->pAggInfo==0
){
/* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
if( pItem->pFExpr==pExpr ) break;
if( NEVER(pItem->pFExpr==pExpr) ) break;
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
+2942 -2032
View File
File diff suppressed because it is too large Load Diff
+219 -96
View File
@@ -4054,7 +4054,13 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = *(int*)pArg;
#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
pFile->iBusyTimeout = !!(*(int*)pArg);
#else
# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
@@ -4307,6 +4313,25 @@ static int unixGetpagesize(void){
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
**
** aLock[SQLITE_SHM_NLOCK]:
** This array records the various locks held by clients on each of the
** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
** locks are held by the process on this slot. If it is set to -1, then
** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
** value is set to a positive value, then it is the number of shared
** locks currently held on the slot.
**
** aMutex[SQLITE_SHM_NLOCK]:
** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
** pShmMutex is used to protect the aLock[] array and the right to
** call fcntl() on unixShmNode.hShm to obtain or release locks.
**
** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
** of mutexes - one for each locking slot. To read or write locking
** slot aLock[iSlot], the caller must hold the corresponding mutex
** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
*/
struct unixShmNode {
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
@@ -4320,10 +4345,11 @@ struct unixShmNode {
char **apRegion; /* Array of mapped shared-memory regions */
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
#endif
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
u8 exclMask; /* Mask of exclusive locks held */
u8 sharedMask; /* Mask of shared locks held */
u8 nextShmId; /* Next available unixShm.id value */
#endif
};
@@ -4406,16 +4432,29 @@ static int unixShmSystemLock(
struct flock f; /* The posix advisory locking structure */
int rc = SQLITE_OK; /* Result code form fcntl() */
/* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
assert( pShmNode->nRef>0 || unixMutexHeld() );
/* Assert that the correct mutex or mutexes are held. */
if( pShmNode->nRef==0 ){
assert( ofst==UNIX_SHM_DMS && n==1 && unixMutexHeld() );
}else{
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int ii;
for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) );
}
#else
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
assert( pShmNode->nRef>0 );
#endif
}
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
/* Locks are within range */
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
if( pShmNode->hShm>=0 ){
int res;
@@ -4426,7 +4465,7 @@ static int unixShmSystemLock(
f.l_len = n;
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
if( res==-1 ){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
#else
rc = SQLITE_BUSY;
@@ -4434,39 +4473,28 @@ static int unixShmSystemLock(
}
}
/* Update the global lock state and do debug tracing */
/* Do debug tracing */
#ifdef SQLITE_DEBUG
{ u16 mask;
OSTRACE(("SHM-LOCK "));
mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
if( rc==SQLITE_OK ){
if( lockType==F_UNLCK ){
OSTRACE(("unlock %d ok", ofst));
pShmNode->exclMask &= ~mask;
pShmNode->sharedMask &= ~mask;
OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
OSTRACE(("read-lock %d ok", ofst));
pShmNode->exclMask &= ~mask;
pShmNode->sharedMask |= mask;
OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
OSTRACE(("write-lock %d ok", ofst));
pShmNode->exclMask |= mask;
pShmNode->sharedMask &= ~mask;
OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
}
}else{
if( lockType==F_UNLCK ){
OSTRACE(("unlock %d failed", ofst));
OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
OSTRACE(("read-lock failed"));
OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
OSTRACE(("write-lock %d failed", ofst));
OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
}
}
OSTRACE((" - afterwards %03x,%03x\n",
pShmNode->sharedMask, pShmNode->exclMask));
}
#endif
return rc;
@@ -4503,6 +4531,11 @@ static void unixShmPurge(unixFile *pFd){
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->pShmMutex);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
for(i=0; i<SQLITE_SHM_NLOCK; i++){
sqlite3_mutex_free(p->aMutex[i]);
}
#endif
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->hShm>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
@@ -4562,7 +4595,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* Do not use a blocking lock here. If the lock cannot be obtained
** immediately, it means some other connection is truncating the
** *-shm file. And after it has done so, it will not release its
** lock, but only downgrade it to a shared lock. So no point in
** blocking here. The call below to obtain the shared DMS lock may
** use a blocking lock. */
int iSaveTimeout = pDbFd->iBusyTimeout;
pDbFd->iBusyTimeout = 0;
#endif
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
pDbFd->iBusyTimeout = iSaveTimeout;
#endif
/* The first connection to attach must truncate the -shm file. We
** truncate to 3 bytes (an arbitrary small number, less than the
** -shm header size) rather than 0 as a system debugging aid, to
@@ -4683,6 +4729,18 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
{
int ii;
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
if( pShmNode->aMutex[ii]==0 ){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
}
}
#endif
}
if( pInode->bProcessLock==0 ){
@@ -4904,9 +4962,11 @@ shmpage_out:
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
return 1;
#else
unixShm *pX;
int aLock[SQLITE_SHM_NLOCK];
assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
memset(aLock, 0, sizeof(aLock));
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
@@ -4924,13 +4984,14 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
#endif
}
#endif
/*
** Change the lock state for a shared-memory segment.
**
** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
** Note that the relationship between SHARED and EXCLUSIVE locks is a little
** different here than in posix. In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back. But one may
** not go from shared to exclusive or from exclusive to shared.
@@ -4945,7 +5006,7 @@ static int unixShmLock(
unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
u16 mask; /* Mask of locks to take or release */
u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
int *aLock;
p = pDbFd->pShm;
@@ -4980,88 +5041,150 @@ static int unixShmLock(
** It is not permitted to block on the RECOVER lock.
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
(ofst!=2) /* not RECOVER */
&& (ofst!=1 || (p->exclMask|p->sharedMask)==0)
&& (ofst!=0 || (p->exclMask|p->sharedMask)<3)
&& (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
));
{
u16 lockMask = (p->exclMask|p->sharedMask);
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
(ofst!=2) /* not RECOVER */
&& (ofst!=1 || lockMask==0 || lockMask==2)
&& (ofst!=0 || lockMask<3)
&& (ofst<3 || lockMask<(1<<ofst))
));
}
#endif
mask = (1<<(ofst+n)) - (1<<ofst);
assert( n>1 || mask==(1<<ofst) );
sqlite3_mutex_enter(pShmNode->pShmMutex);
assert( assertLockingArrayOk(pShmNode) );
if( flags & SQLITE_SHM_UNLOCK ){
if( (p->exclMask|p->sharedMask) & mask ){
int ii;
int bUnlock = 1;
/* Check if there is any work to do. There are three cases:
**
** a) An unlock operation where there are locks to unlock,
** b) An shared lock where the requested lock is not already held
** c) An exclusive lock where the requested lock is not already held
**
** The SQLite core never requests an exclusive lock that it already holds.
** This is assert()ed below.
*/
assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
|| 0==(p->exclMask & mask)
);
if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
|| (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
|| (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
){
for(ii=ofst; ii<ofst+n; ii++){
if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
bUnlock = 0;
}
}
if( bUnlock ){
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
memset(&aLock[ofst], 0, sizeof(int)*n);
}
}else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
assert( n==1 && aLock[ofst]>1 );
aLock[ofst]--;
}
/* Undo the local locks */
if( rc==SQLITE_OK ){
p->exclMask &= ~mask;
p->sharedMask &= ~mask;
/* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any
** other thread is holding this mutex, then it is either holding or about
** to hold a lock exclusive to the one being requested, and we may
** therefore return SQLITE_BUSY to the caller.
**
** Doing this prevents some deadlock scenarios. For example, thread 1 may
** be a checkpointer blocked waiting on the WRITER lock. And thread 2
** may be a normal SQL client upgrading to a write transaction. In this
** case thread 2 does a non-blocking request for the WRITER lock. But -
** if it were to use sqlite3_mutex_enter() then it would effectively
** become a (doomed) blocking request, as thread 2 would block until thread
** 1 obtained WRITER and released the mutex. Since thread 2 already holds
** a lock on a read-locking slot at this point, this breaks the
** anti-deadlock rules (see above). */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int iMutex;
for(iMutex=ofst; iMutex<ofst+n; iMutex++){
if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
rc = sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
if( rc!=SQLITE_OK ) break;
}else{
sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
}
}
}else if( flags & SQLITE_SHM_SHARED ){
assert( n==1 );
assert( (p->exclMask & (1<<ofst))==0 );
if( (p->sharedMask & mask)==0 ){
if( aLock[ofst]<0 ){
rc = SQLITE_BUSY;
}else if( aLock[ofst]==0 ){
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
}
#else
sqlite3_mutex_enter(pShmNode->pShmMutex);
#endif
/* Get the local shared locks */
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
aLock[ofst]++;
}
}
}else{
/* Make sure no sibling connections hold locks that will block this
** lock. If any do, return SQLITE_BUSY right away. */
int ii;
for(ii=ofst; ii<ofst+n; ii++){
assert( (p->sharedMask & mask)==0 );
if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
rc = SQLITE_BUSY;
break;
}
}
/* Get the exclusive locks at the system level. Then if successful
** also update the in-memory values. */
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
if( flags & SQLITE_SHM_UNLOCK ){
/* Case (a) - unlock. */
int bUnlock = 1;
assert( (p->exclMask & p->sharedMask)==0 );
assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
/* If this is a SHARED lock being unlocked, it is possible that other
** clients within this process are holding the same SHARED lock. In
** this case, set bUnlock to 0 so that the posix lock is not removed
** from the file-descriptor below. */
if( flags & SQLITE_SHM_SHARED ){
assert( n==1 );
assert( aLock[ofst]>=1 );
if( aLock[ofst]>1 ){
bUnlock = 0;
aLock[ofst]--;
p->sharedMask &= ~mask;
}
}
if( bUnlock ){
rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
memset(&aLock[ofst], 0, sizeof(int)*n);
p->sharedMask &= ~mask;
p->exclMask &= ~mask;
}
}
}else if( flags & SQLITE_SHM_SHARED ){
/* Case (b) - a shared lock. */
if( aLock[ofst]<0 ){
/* An exclusive lock is held by some other connection. BUSY. */
rc = SQLITE_BUSY;
}else if( aLock[ofst]==0 ){
rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
}
/* Get the local shared locks */
if( rc==SQLITE_OK ){
p->sharedMask |= mask;
aLock[ofst]++;
}
}else{
/* Case (c) - an exclusive lock. */
int ii;
assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
assert( (p->sharedMask & mask)==0 );
p->exclMask |= mask;
assert( (p->exclMask & mask)==0 );
/* Make sure no sibling connections hold locks that will block this
** lock. If any do, return SQLITE_BUSY right away. */
for(ii=ofst; ii<ofst+n; ii++){
aLock[ii] = -1;
if( aLock[ii] ){
rc = SQLITE_BUSY;
break;
}
}
/* Get the exclusive locks at the system level. Then if successful
** also update the in-memory values. */
if( rc==SQLITE_OK ){
rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
if( rc==SQLITE_OK ){
p->exclMask |= mask;
for(ii=ofst; ii<ofst+n; ii++){
aLock[ii] = -1;
}
}
}
}
assert( assertLockingArrayOk(pShmNode) );
}
/* Drop the mutexes acquired above. */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
for(iMutex--; iMutex>=ofst; iMutex--){
sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
}
#else
sqlite3_mutex_leave(pShmNode->pShmMutex);
#endif
}
assert( assertLockingArrayOk(pShmNode) );
sqlite3_mutex_leave(pShmNode->pShmMutex);
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
+2 -1
View File
@@ -1779,7 +1779,8 @@ void sqlite3Pragma(
if( pVTab->pModule->iVersion<4 ) continue;
if( pVTab->pModule->xIntegrity==0 ) continue;
sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
sqlite3VdbeAppendP4(v, pTab, P4_TABLE);
pTab->nTabRef++;
sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, a1);
+1
View File
@@ -868,6 +868,7 @@ static int sqlite3LockAndPrepare(
assert( (rc&db->errMask)==rc );
db->busyHandler.nBusy = 0;
sqlite3_mutex_leave(db->mutex);
assert( rc==SQLITE_OK || (*ppStmt)==0 );
return rc;
}
+1 -1
View File
@@ -1369,7 +1369,7 @@ void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
/*****************************************************************************
** Reference counted string storage
** Reference counted string/blob storage
*****************************************************************************/
/*
+6 -1
View File
@@ -1249,11 +1249,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
pExpr->op2++;
pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -1812,6 +1813,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
@@ -1836,6 +1838,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
pOuterNC->nNestedSelect--;
}
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
+11 -9
View File
@@ -251,6 +251,7 @@ INCLUDE ../ext/consio/console_io.h
INCLUDE ../ext/consio/console_io.c
#ifndef SQLITE_SHELL_FIDDLE
/* From here onward, fgets() is redirected to the console_io library. */
# define fgets(b,n,f) fGetsUtf8(b,n,f)
/*
@@ -275,6 +276,7 @@ INCLUDE ../ext/consio/console_io.c
# define eputz(z) ePutsUtf8(z)
# define eputf ePrintfUtf8
# define oputb(buf,na) oPutbUtf8(buf,na)
#else
/* For Fiddle, all console handling and emit redirection is omitted. */
# define sputz(fp,z) fputs(z,fp)
@@ -358,7 +360,7 @@ static void endTimer(void){
sqlite3_int64 iEnd = timeOfDay();
struct rusage sEnd;
getrusage(RUSAGE_SELF, &sEnd);
oputf("Run Time: real %.3f user %f sys %f\n",
sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
(iEnd - iBegin)*0.001,
timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
@@ -437,7 +439,7 @@ static void endTimer(void){
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
sqlite3_int64 ftWallEnd = timeOfDay();
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
oputf("Run Time: real %.3f user %f sys %f\n",
sputf(stdout, "Run Time: real %.3f user %f sys %f\n",
(ftWallEnd - ftWallBegin)*0.001,
timeDiff(&ftUserBegin, &ftUserEnd),
timeDiff(&ftKernelBegin, &ftKernelEnd));
@@ -11858,14 +11860,14 @@ static void printBold(const char *zText){
FOREGROUND_RED|FOREGROUND_INTENSITY
);
#endif
oputz(zText);
sputz(stdout, zText);
#if !SQLITE_OS_WINRT
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
#endif
}
#else
static void printBold(const char *zText){
oputf("\033[1m%s\033[0m", zText);
sputf(stdout, "\033[1m%s\033[0m", zText);
}
#endif
@@ -12332,8 +12334,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
}else if( cli_strcmp(z,"-bail")==0 ){
/* No-op. The bail_on_error flag should already be set. */
}else if( cli_strcmp(z,"-version")==0 ){
oputf("%s %s (%d-bit)\n", sqlite3_libversion(), sqlite3_sourceid(),
8*(int)sizeof(char*));
sputf(stdout, "%s %s (%d-bit)\n",
sqlite3_libversion(), sqlite3_sourceid(), 8*(int)sizeof(char*));
return 0;
}else if( cli_strcmp(z,"-interactive")==0 ){
/* already handled */
@@ -12465,13 +12467,13 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
#else
# define SHELL_CIO_CHAR_SET ""
#endif
oputf("SQLite version %s %.19s%s\n" /*extra-version-info*/
sputf(stdout, "SQLite version %s %.19s%s\n" /*extra-version-info*/
"Enter \".help\" for usage hints.\n",
sqlite3_libversion(), sqlite3_sourceid(), SHELL_CIO_CHAR_SET);
if( warnInmemoryDb ){
oputz("Connected to a ");
sputz(stdout, "Connected to a ");
printBold("transient in-memory database");
oputz(".\nUse \".open FILENAME\" to reopen on a"
sputz(stdout, ".\nUse \".open FILENAME\" to reopen on a"
" persistent database.\n");
}
zHistory = getenv("SQLITE_HISTORY");
+5 -3
View File
@@ -3954,15 +3954,17 @@ void sqlite3_free_filename(sqlite3_filename);
** </ul>
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
** text that describes the error, as either UTF-8 or UTF-16 respectively.
** text that describes the error, as either UTF-8 or UTF-16 respectively,
** or NULL if no error message is available.
** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
** ^The sqlite3_errstr() interface returns the English-language text
** that describes the [result code], as UTF-8.
** ^The sqlite3_errstr(E) interface returns the English-language text
** that describes the [result code] E, as UTF-8, or NULL if E is not an
** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
+6 -2
View File
@@ -2114,11 +2114,11 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, iArg, xFunc) \
#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\
SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\
((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -3399,6 +3399,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
u32 nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -4115,6 +4116,9 @@ struct sqlite3_str {
**
** 3. Make a (read-only) copy of a read-only RCStr string using
** sqlite3RCStrRef().
**
** "String" is in the name, but an RCStr object can also be used to hold
** binary data.
*/
struct RCStr {
u64 nRCRef; /* Number of references */
+1 -1
View File
@@ -781,7 +781,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
assert( pExpr->x.pList->nExpr==2 );
pY = pExpr->x.pList->a[0].pExpr;
pZ = pExpr->x.pList->a[1].pExpr;
sqlite3TreeViewLine(pView, "BETWEEN");
sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
sqlite3TreeViewExpr(pView, pX, 1);
sqlite3TreeViewExpr(pView, pY, 1);
sqlite3TreeViewExpr(pView, pZ, 0);
+7 -4
View File
@@ -2034,7 +2034,7 @@ case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
sqlite3VdbeMemIntegerify(pIn1);
pIn1->u.i += pOp->p2;
*(u64*)&pIn1->u.i += (u64)pOp->p2;
break;
}
@@ -8180,9 +8180,10 @@ case OP_VCheck: { /* out2 */
pOut = &aMem[pOp->p2];
sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
assert( pOp->p4type==P4_TABLE );
assert( pOp->p4type==P4_TABLEREF );
pTab = pOp->p4.pTab;
assert( pTab!=0 );
assert( pTab->nTabRef>0 );
assert( IsVirtual(pTab) );
if( pTab->u.vtab.p==0 ) break;
pVtab = pTab->u.vtab.p->pVtab;
@@ -8191,13 +8192,11 @@ case OP_VCheck: { /* out2 */
assert( pModule!=0 );
assert( pModule->iVersion>=4 );
assert( pModule->xIntegrity!=0 );
pTab->nTabRef++;
sqlite3VtabLock(pTab->u.vtab.p);
assert( pOp->p1>=0 && pOp->p1<db->nDb );
rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
pOp->p3, &zErr);
sqlite3VtabUnlock(pTab->u.vtab.p);
sqlite3DeleteTable(db, pTab);
if( rc ){
sqlite3_free(zErr);
goto abort_due_to_error;
@@ -8322,6 +8321,7 @@ case OP_VColumn: { /* ncycle */
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
FuncDef nullFunc;
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur!=0 );
@@ -8339,6 +8339,9 @@ case OP_VColumn: { /* ncycle */
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
sContext.enc = encoding;
nullFunc.pUserData = 0;
nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE;
sContext.pFunc = &nullFunc;
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
sqlite3VdbeMemSetNull(pDest);
+1
View File
@@ -126,6 +126,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
+10 -3
View File
@@ -152,7 +152,15 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
sqlite3_mutex *mutex;
#endif
#ifdef SQLITE_ENABLE_API_ARMOR
if( pStmt==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
#if SQLITE_THREADSAFE
mutex = p->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
for(i=0; i<p->nVar; i++){
@@ -942,9 +950,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
void *sqlite3_user_data(sqlite3_context *p){
#ifdef SQLITE_ENABLE_API_ARMOR
if( p==0 ) return 0;
#else
assert( p && p->pFunc );
#endif
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
+5 -1
View File
@@ -1400,6 +1400,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
break;
}
case P4_TABLEREF: {
if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4);
break;
}
}
}
@@ -1527,7 +1531,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full(
int n
){
if( pOp->p4type ){
freeP4(p->db, pOp->p4type, pOp->p4.p);
assert( pOp->p4type > P4_FREE_IF_LE );
pOp->p4type = 0;
pOp->p4.p = 0;
}
+52 -23
View File
@@ -2004,6 +2004,19 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/*
** Attempt to enable blocking locks that block for nMs ms. Return 1 if
** blocking locks are successfully enabled, or 0 otherwise.
*/
static int walEnableBlockingMs(Wal *pWal, int nMs){
int rc = sqlite3OsFileControl(
pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
);
return (rc==SQLITE_OK);
}
/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
** they are supported by the VFS, and (b) the database handle is configured
@@ -2015,11 +2028,7 @@ static int walEnableBlocking(Wal *pWal){
if( pWal->db ){
int tmout = pWal->db->busyTimeout;
if( tmout ){
int rc;
rc = sqlite3OsFileControl(
pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
);
res = (rc==SQLITE_OK);
res = walEnableBlockingMs(pWal, tmout);
}
}
return res;
@@ -2068,20 +2077,10 @@ void sqlite3WalDb(Wal *pWal, sqlite3 *db){
pWal->db = db;
}
/*
** Take an exclusive WRITE lock. Blocking if so configured.
*/
static int walLockWriter(Wal *pWal){
int rc;
walEnableBlocking(pWal);
rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
walDisableBlocking(pWal);
return rc;
}
#else
# define walEnableBlocking(x) 0
# define walDisableBlocking(x)
# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
# define walEnableBlockingMs(pWal, ms) 0
# define sqlite3WalDb(pWal, db)
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
@@ -2682,7 +2681,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
}
}else{
int bWriteLock = pWal->writeLock;
if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
if( bWriteLock
|| SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -2690,7 +2691,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* If the wal-index header is still malformed even while holding
** a WRITE lock, it can only mean that the header is corrupted and
** needs to be reconstructed. So run recovery to do exactly that.
*/
** Disable blocking locks first. */
walDisableBlocking(pWal);
rc = walIndexRecover(pWal);
*pChanged = 1;
}
@@ -2957,6 +2959,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
u32 mxFrame; /* Wal frame to lock to */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int nBlockTmout = 0;
#endif
assert( pWal->readLock<0 ); /* Not currently locked */
@@ -2987,6 +2992,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return SQLITE_PROTOCOL;
}
if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
** to block for locks for approximately nDelay us. This affects three
** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
** first attempted read fails, and (c) the shared lock taken on the DMS
** slot in os_unix.c. All three of these locks are attempted from within
** the call to walIndexReadHdr() below. */
nBlockTmout = (nDelay+998) / 1000;
if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
nDelay = 1;
}
#endif
sqlite3OsSleep(pWal->pVfs, nDelay);
}
@@ -2995,6 +3013,10 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( pWal->bShmUnreliable==0 ){
rc = walIndexReadHdr(pWal, pChanged);
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
walDisableBlocking(pWal);
if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
#endif
if( rc==SQLITE_BUSY ){
/* If there is not a recovery running in another thread or process
** then convert BUSY errors to WAL_RETRY. If recovery is known to
@@ -3109,9 +3131,12 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
}
(void)walEnableBlockingMs(pWal, nBlockTmout);
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
walDisableBlocking(pWal);
if( rc ){
return rc==SQLITE_BUSY ? WAL_RETRY : rc;
assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
}
/* Now that the read-lock has been obtained, check that neither the
** value in the aReadMark[] array or the contents of the wal-index
@@ -4204,10 +4229,9 @@ int sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
/* Enable blocking locks, if possible. If blocking locks are successfully
** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
/* Enable blocking locks, if possible. */
sqlite3WalDb(pWal, db);
(void)walEnableBlocking(pWal);
if( xBusy2 ) (void)walEnableBlocking(pWal);
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file.
@@ -4248,9 +4272,14 @@ int sqlite3WalCheckpoint(
/* Read the wal-index header. */
SEH_TRY {
if( rc==SQLITE_OK ){
/* For a passive checkpoint, do not re-enable blocking locks after
** reading the wal-index header. A passive checkpoint should not block
** or invoke the busy handler. The only lock such a checkpoint may
** attempt to obtain is a lock on a read-slot, and it should give up
** immediately and do a partial checkpoint if it cannot obtain it. */
walDisableBlocking(pWal);
rc = walIndexReadHdr(pWal, &isChanged);
(void)walEnableBlocking(pWal);
if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal);
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
}
+10
View File
@@ -678,12 +678,22 @@ static void translateColumnToCopy(
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
#ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
}
#endif
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + iRegister;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
}else if( pOp->opcode==OP_Rowid ){
#ifdef SQLITE_DEBUG
if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
}
#endif
pOp->opcode = OP_Sequence;
pOp->p1 = iAutoidxCur;
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+112
View File
@@ -358,7 +358,119 @@ do_execsql_test 6.2.2 {
FROM t2 GROUP BY 'constant_string';
} {{}}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 7.0 {
CREATE TABLE invoice (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
amount DOUBLE PRECISION DEFAULT NULL,
name VARCHAR(100) DEFAULT NULL
);
INSERT INTO invoice (amount, name) VALUES
(4.0, 'Michael'), (15.0, 'Bara'), (4.0, 'Michael'), (6.0, 'John');
}
do_execsql_test 7.1 {
SELECT sum(amount), name
from invoice
group by name
having (select v > 6 from (select sum(amount) v) t)
} {
15.0 Bara
8.0 Michael
}
do_execsql_test 7.2 {
SELECT (select 1 from (select sum(amount))) FROM invoice
} {1}
do_execsql_test 8.0 {
CREATE TABLE t1(x INT);
INSERT INTO t1 VALUES(100);
INSERT INTO t1 VALUES(20);
INSERT INTO t1 VALUES(3);
SELECT (SELECT y FROM (SELECT sum(x) AS y) AS t2 ) FROM t1;
} {123}
do_execsql_test 8.1 {
SELECT (
SELECT y FROM (
SELECT z AS y FROM (SELECT sum(x) AS z) AS t2
)
) FROM t1;
} {123}
do_execsql_test 8.2 {
SELECT (
SELECT a FROM (
SELECT y AS a FROM (
SELECT z AS y FROM (SELECT sum(x) AS z) AS t2
)
)
) FROM t1;
} {123}
#-------------------------------------------------------------------------
# dbsqlfuzz 04408efc51ae46897c4c122b407412045ed221b4
#
reset_db
do_execsql_test 9.1 {
WITH out(i, j, k) AS (
VALUES(1234, 5678, 9012)
)
SELECT (
SELECT (
SELECT min(abc) = ( SELECT ( SELECT 1234 fROM (SELECT abc) ) )
FROM (
SELECT sum( out.i ) + ( SELECT sum( out.i ) ) AS abc FROM (SELECT out.j)
)
)
) FROM out;
} {0}
do_execsql_test 9.2 {
CREATE TABLE t1(a);
CREATE TABLE t2(b);
INSERT INTO t1 VALUES(1), (2), (3);
INSERT INTO t2 VALUES(4), (5), (6);
SELECT (
SELECT min(y) + (SELECT x) FROM (
SELECT sum(a) AS x, b AS y FROM t2
)
)
FROM t1;
} {10}
do_execsql_test 9.3 {
SELECT (
SELECT min(y) + (SELECT (SELECT x)) FROM (
SELECT sum(a) AS x, b AS y FROM t2
)
)
FROM t1;
} {10}
do_execsql_test 9.4 {
SELECT (
SELECT (SELECT x) FROM (
SELECT sum(a) AS x, b AS y FROM t2
) GROUP BY y
)
FROM t1;
} {6}
do_execsql_test 9.5 {
SELECT (
SELECT (SELECT (SELECT x)) FROM (
SELECT sum(a) AS x, b AS y FROM t2
) GROUP BY y
)
FROM t1;
} {6}
+5
View File
@@ -146,6 +146,8 @@ datetest 2.49 {datetime('2003-10-22 12:24','0000 second')} {2003-10-22 12:24:00}
datetest 2.50 {datetime('2003-10-22 12:24','0001 second')} {2003-10-22 12:24:01}
datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL
datetest 2.60 {datetime('2023-02-31')} {2023-03-03 00:00:00}
datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post
datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999
@@ -452,6 +454,9 @@ datetest 13.31 {date('2001-01-01','+1.5 years')} {2002-07-02}
datetest 13.32 {date('2002-01-01','+1.5 years')} {2003-07-02}
datetest 13.33 {date('2002-01-01','-1.5 years')} {2000-07-02}
datetest 13.34 {date('2001-01-01','-1.5 years')} {1999-07-02}
datetest 13.35 {date('2023-02-28')} {2023-02-28}
datetest 13.36 {date('2023-02-29')} {2023-03-01}
datetest 13.37 {date('2023-04-31')} {2023-05-01}
# Test for issues reported by BareFeet (list.sql at tandb.com.au)
# on mailing list on 2008-06-12.
+24
View File
@@ -0,0 +1,24 @@
.mode qbox
.timer on
.param set $label 'q87'
SELECT rowid, x->>$label FROM data1 WHERE x->>$label IS NOT NULL;
CREATE TEMP TABLE t2(x JSON TEXT);
WITH RECURSIVE
c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<25000),
array1(y) AS (
SELECT json_group_array(
json_object('x',x,'y',random(),'z',hex(randomblob(50)))
)
FROM c
),
c2(n) AS (VALUES(1) UNION ALL SELECT n+1 FROM c2 WHERE n<5)
INSERT INTO t2(x)
SELECT jsonb_object('a',n,'b',n*2,'c',y,'d',3,'e',5,'f',6) FROM array1, c2;
CREATE INDEX t2x1 ON t2(x->>'a');
CREATE INDEX t2x2 ON t2(x->>'b');
CREATE INDEX t2x3 ON t2(x->>'e');
CREATE INDEX t2x4 ON t2(x->>'f');
UPDATE t2 SET x=jsonb_replace(x,'$.f',(x->>'f')+1);
UPDATE t2 SET x=jsonb_set(x,'$.e',(x->>'f')-1);
UPDATE t2 SET x=jsonb_remove(x,'$.d');
+14 -4
View File
@@ -40,6 +40,7 @@ doCachegrind=1
doVdbeProfile=0
doWal=1
doDiff=1
doJsonB=0
while test "$1" != ""; do
case $1 in
--nodiff)
@@ -54,6 +55,9 @@ while test "$1" != ""; do
--gcc7)
CC=gcc-7
;;
--jsonb)
doJsonB=1
;;
-*)
CC_OPTS="$CC_OPTS $1"
;;
@@ -69,12 +73,18 @@ rm -f cachegrind.out.* jsonshell
$CC -g -Os -Wall -I. $CC_OPTS ./shell.c ./sqlite3.c -o jsonshell -ldl -lpthread
ls -l jsonshell | tee -a summary-$NAME.txt
home=`echo $0 | sed -e 's,/[^/]*$,,'`
echo ./jsonshell json100mb.db "<$home/json-q1.txt"
valgrind --tool=cachegrind ./jsonshell json100mb.db <$home/json-q1.txt \
2>&1 | tee -a summary-$NAME.txt
if test $doJsonB -eq 1; then
echo ./jsonshell json100mb_b.db "<$home/json-q1-b.txt"
valgrind --tool=cachegrind ./jsonshell json100mb_b.db <$home/json-q1-b.txt \
2>&1 | tee -a summary-$NAME.txt
else
echo ./jsonshell json100mb.db "<$home/json-q1.txt"
valgrind --tool=cachegrind ./jsonshell json100mb.db <$home/json-q1.txt \
2>&1 | tee -a summary-$NAME.txt
fi
cg_anno.tcl cachegrind.out.* >jout-$NAME.txt
echo '*****************************************************' >>jout-$NAME.txt
sed 's/^[0-9=-]\{9\}/==00000==/' summary-$NAME.txt >>jout-$NAME.txt
if test "$NAME" != "$BASELINE"; then
if test "$NAME" != "$BASELINE" -a $doDiff -ne 0; then
fossil xdiff --tk -c 20 jout-$BASELINE.txt jout-$NAME.txt
fi
+119 -11
View File
@@ -36,6 +36,9 @@ do_execsql_test json101-1.2 {
do_catchsql_test json101-1.3 {
SELECT json_array(1,printf('%.1000c','x'),x'abcd',3);
} {1 {JSON cannot hold BLOB values}}
do_catchsql_test json101-1.3b {
SELECT jsonb_array(1,printf('%.1000c','x'),x'abcd',3);
} {1 {JSON cannot hold BLOB values}}
do_execsql_test json101-1.4 {
SELECT json_array(-9223372036854775808,9223372036854775807,0,1,-1,
0.0, 1.0, -1.0, -1e99, +2e100,
@@ -47,36 +50,83 @@ do_execsql_test json101-1.4 {
'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
99);
} {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]}
do_execsql_test json101-1.4b {
SELECT json(jsonb_array(-9223372036854775808,9223372036854775807,0,1,-1,
0.0, 1.0, -1.0, -1e99, +2e100,
'one','two','three',
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, NULL, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ',
99));
} {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]}
do_execsql_test json101-2.1 {
SELECT json_object('a',1,'b',2.5,'c',null,'d','String Test');
} {{{"a":1,"b":2.5,"c":null,"d":"String Test"}}}
do_execsql_test json101-2.1b {
SELECT json(jsonb_object('a',1,'b',2.5,'c',null,'d','String Test'));
} {{{"a":1,"b":2.5,"c":null,"d":"String Test"}}}
do_catchsql_test json101-2.2 {
SELECT json_object('a',printf('%.1000c','x'),2,2.5);
} {1 {json_object() labels must be TEXT}}
do_catchsql_test json101-2.2b {
SELECT jsonb_object('a',printf('%.1000c','x'),2,2.5);
} {1 {json_object() labels must be TEXT}}
do_execsql_test json101-2.2.2 {
SELECT json_object('a',json_array('xyx',77,4.5),'x',2.5);
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.2b {
SELECT json(jsonb_object('a',json_array('xyx',77,4.5),'x',2.5));
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.3 {
SELECT json_object('a',jsonb_array('xyx',77,4.5),'x',2.5);
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_execsql_test json101-2.2.3b {
SELECT json(jsonb_object('a',jsonb_array('xyx',77,4.5),'x',2.5));
} {{{"a":["xyx",77,4.5],"x":2.5}}}
do_catchsql_test json101-2.3 {
SELECT json_object('a',1,'b');
} {1 {json_object() requires an even number of arguments}}
do_catchsql_test json101-2.4 {
SELECT json_object('a',printf('%.1000c','x'),'b',x'abcd');
} {1 {JSON cannot hold BLOB values}}
do_execsql_test json101-2.5 {
SELECT json_object('a',printf('%.10c','x'),'b',jsonb_array(1,2,3));
} {{{"a":"xxxxxxxxxx","b":[1,2,3]}}}
do_execsql_test json101-3.1 {
SELECT json_replace('{"a":1,"b":2}','$.a','[3,4,5]');
} {{{"a":"[3,4,5]","b":2}}}
do_execsql_test json101-3.1b {
SELECT json(jsonb_replace('{"a":1,"b":2}','$.a','[3,4,5]'));
} {{{"a":"[3,4,5]","b":2}}}
do_execsql_test json101-3.2 {
SELECT json_replace('{"a":1,"b":2}','$.a',json('[3,4,5]'));
} {{{"a":[3,4,5],"b":2}}}
do_execsql_test json101-3.2b {
SELECT json_replace('{"a":1,"b":2}','$.a',jsonb('[3,4,5]'));
} {{{"a":[3,4,5],"b":2}}}
do_execsql_test json101-3.3 {
SELECT json_type(json_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b');
} {text}
do_execsql_test json101-3.3b {
SELECT json_type(jsonb_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b');
} {text}
do_execsql_test json101-3.4 {
SELECT json_type(json_set('{"a":1,"b":2}','$.b',json('{"x":3,"y":4}')),'$.b');
} {object}
do_execsql_test json101-3.4b {
SELECT json_type(jsonb_set('{"a":1,"b":2}','$.b',jsonb('{"x":3,"y":4}')),'$.b');
} {object}
ifcapable vtab {
do_execsql_test json101-3.5 {
SELECT fullkey, atom, '|' FROM json_tree(json_set('{}','$.x',123,'$.x',456));
} {{$} {} | {$.x} 456 |}
do_execsql_test json101-3.5 {
SELECT fullkey, atom, '|' FROM json_tree(json_set('{}','$.x',123,'$.x',456));
} {{$} {} | {$.x} 456 |}
do_execsql_test json101-3.5b {
SELECT fullkey, atom, '|' FROM json_tree(jsonb_set('{}','$.x',123,'$.x',456));
} {{$} {} | {$.x} 456 |}
}
# Per rfc7159, any JSON value is allowed at the top level, and whitespace
@@ -131,6 +181,13 @@ do_execsql_test json101-4.10 {
WHERE json_extract(x,'$')<>x
AND json_type(x) IN ('object','array');
} {4}
do_execsql_test json101-4.10b {
CREATE TABLE j1b AS SELECT jsonb(x) AS "x" FROM j1;
SELECT count(*) FROM j1b WHERE json_type(x) IN ('object','array');
SELECT json(x) FROM j1b
WHERE json_extract(x,'$')<>json(x)
AND json_type(x) IN ('object','array');
} {4}
do_execsql_test json101-5.1 {
CREATE TABLE j2(id INTEGER PRIMARY KEY, json, src);
@@ -258,11 +315,17 @@ do_execsql_test json101-5.1 {
}
]','https://adobe.github.io/Spry/samples/data_region/JSONDataSetSample.html');
SELECT count(*) FROM j2;
} {3}
CREATE TABLE j2b(id INTEGER PRIMARY KEY, json, src);
INSERT INTO J2b(id,json,src) SELECT id, jsonb(json), src FROM j2;
SELECT count(*) FROM j2b;
} {3 3}
do_execsql_test json101-5.2 {
SELECT id, json_valid(json), json_type(json), '|' FROM j2 ORDER BY id;
} {1 1 object | 2 1 object | 3 1 array |}
do_execsql_test json101-5.2b {
SELECT id, json_valid(json,5), json_type(json), '|' FROM j2b ORDER BY id;
} {1 1 object | 2 1 object | 3 1 array |}
ifcapable !vtab {
finish_test
@@ -277,6 +340,12 @@ do_execsql_test json101-5.3 {
WHERE fullkey!=(path || CASE WHEN typeof(key)=='integer' THEN '['||key||']'
ELSE '.'||key END);
} {}
do_execsql_test json101-5.3b {
SELECT j2b.rowid, jx.rowid, fullkey, path, key
FROM j2b, json_tree(j2b.json) AS jx
WHERE fullkey!=(path || CASE WHEN typeof(key)=='integer' THEN '['||key||']'
ELSE '.'||key END);
} {}
do_execsql_test json101-5.4 {
SELECT j2.rowid, jx.rowid, fullkey, path, key
FROM j2, json_each(j2.json) AS jx
@@ -371,6 +440,13 @@ do_execsql_test json101-8.1 {
UPDATE t8 SET b=json_array(a);
SELECT b FROM t8;
} {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}}
do_execsql_test json101-8.1b {
DROP TABLE IF EXISTS t8;
CREATE TABLE t8(a,b);
INSERT INTO t8(a) VALUES('abc' || char(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35) || 'xyz');
UPDATE t8 SET b=jsonb_array(a);
SELECT json(b) FROM t8;
} {{["abc\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#xyz"]}}
do_execsql_test json101-8.2 {
SELECT a=json_extract(b,'$[0]') FROM t8;
} {1}
@@ -401,7 +477,7 @@ do_execsql_test json101-9.4 {
SELECT json_quote(null);
} {"null"}
do_catchsql_test json101-9.5 {
SELECT json_quote(x'30313233');
SELECT json_quote(x'3031323334');
} {1 {JSON cannot hold BLOB values}}
do_catchsql_test json101-9.6 {
SELECT json_quote(123,456)
@@ -769,14 +845,23 @@ do_execsql_test json101-12.100 {
}
}');
} {}
do_execsql_test json101-12.110 {
SELECT json_remove(x, '$.settings.layer2."dis.legomenon".forceDisplay')
FROM t12;
} {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}}
do_execsql_test json101-12.110b {
SELECT json_remove(jsonb(x), '$.settings.layer2."dis.legomenon".forceDisplay')
FROM t12;
} {{{"settings":{"layer2":{"hapax.legomenon":{"forceDisplay":true,"transliterate":true,"add.footnote":true,"summary.report":true},"dis.legomenon":{"transliterate":false,"add.footnote":false,"summary.report":true},"tris.legomenon":{"forceDisplay":true,"transliterate":false,"add.footnote":false,"summary.report":false}}}}}}
do_execsql_test json101-12.120 {
SELECT json_extract(x, '$.settings.layer2."tris.legomenon"."summary.report"')
FROM t12;
} {0}
do_execsql_test json101-12.120b {
SELECT json_extract(jsonb(x), '$.settings.layer2."tris.legomenon"."summary.report"')
FROM t12;
} {0}
# 2018-01-26
# ticket https://www.sqlite.org/src/tktview/80177f0c226ff54f6ddd41
@@ -840,16 +925,16 @@ do_execsql_test json101-14.170 {
#
do_execsql_test json101-15.100 {
SELECT * FROM JSON_EACH('{"a":1, "b":2}');
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.110 {
SELECT xyz.* FROM JSON_EACH('{"a":1, "b":2}') AS xyz;
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.120 {
SELECT * FROM (JSON_EACH('{"a":1, "b":2}'));
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
do_execsql_test json101-15.130 {
SELECT xyz.* FROM (JSON_EACH('{"a":1, "b":2}')) AS xyz;
} {a 1 integer 1 2 {} {$.a} {$} b 2 integer 2 4 {} {$.b} {$}}
} {a 1 integer 1 1 {} {$.a} {$} b 2 integer 2 5 {} {$.b} {$}}
# 2019-11-10
# Mailing list bug report on the handling of surrogate pairs
@@ -889,7 +974,7 @@ do_execsql_test json101-18.4 {
} {6}
do_catchsql_test json101-18.5 {
SELECT json_extract('{"":8}', '$.');
} {1 {JSON path error near ''}}
} {1 {bad JSON path: '$.'}}
# 2022-08-29 https://sqlite.org/forum/forumpost/9b9e4716c0d7bbd1
# This is not a problem specifically with JSON functions. It is
@@ -1054,6 +1139,29 @@ do_execsql_test json101-23.2 {
FROM (SELECT json_set('[]','$[#]',0,'$[#]',1) AS j);
} {{[0,1]} 0 1}
# Insert/Set/Replace where the path specifies substructure that
# does not yet exist
#
proc tx x {return [string map [list ( \173 ) \175 ' \042 < \133 > \135] $x]}
foreach {id start path ins set repl} {
1 {{}} {$.a.b.c} ('a':('b':('c':9))) ('a':('b':('c':9))) ()
2 {{a:4}} {$.a.b.c} ('a':4) ('a':4) ('a':4)
3 {{a:{}}} {$.a.b.c} ('a':('b':('c':9))) ('a':('b':('c':9))) ('a':())
4 {[0,1,2]} {$[3].a[0].b} <0,1,2,('a':<('b':9)>)> <0,1,2,('a':<('b':9)>)> <0,1,2>
5 {[0,1,2]} {$[1].a[0].b} <0,1,2> <0,1,2> <0,1,2>
6 {[0,{},2]} {$[1].a[0].b} <0,('a':<('b':9)>),2> <0,('a':<('b':9)>),2> <0,(),2>
7 {[0,1,2]} {$[3][0].b} <0,1,2,<('b':9)>> <0,1,2,<('b':9)>> <0,1,2>
8 {[0,1,2]} {$[1][0].b} <0,1,2> <0,1,2> <0,1,2>
} {
do_execsql_test json101-24.$id.insert {
SELECT json_insert($start,$path,9);
} [list [tx $ins]]
do_execsql_test json101-24.$id.set {
SELECT json_set($start,$path,9);
} [list [tx $set]]
do_execsql_test json101-24.$id.replace {
SELECT json_replace($start,$path,9);
} [list [tx $repl]]
}
finish_test
+349 -3
View File
@@ -21,159 +21,492 @@ source $testdir/tester.tcl
do_execsql_test json102-100 {
SELECT json_object('ex','[52,3.14159]');
} {{{"ex":"[52,3.14159]"}}}
do_execsql_test json102-100b {
SELECT json(jsonb_object('ex','[52,3.14159]'));
} {{{"ex":"[52,3.14159]"}}}
do_execsql_test json102-110 {
SELECT json_object('ex',json('[52,3.14159]'));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-2 {
SELECT json(jsonb_object('ex',json('[52,3.14159]')));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-3 {
SELECT json_object('ex',jsonb('[52,3.14159]'));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-110-3 {
SELECT json(jsonb_object('ex',jsonb('[52,3.14159]')));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120 {
SELECT json_object('ex',json_array(52,3.14159));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-2 {
SELECT json(jsonb_object('ex',json_array(52,3.14159)));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-3 {
SELECT json_object('ex',jsonb_array(52,3.14159));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-120-4 {
SELECT json(jsonb_object('ex',jsonb_array(52,3.14159)));
} {{{"ex":[52,3.14159]}}}
do_execsql_test json102-130 {
SELECT json(' { "this" : "is", "a": [ "test" ] } ');
} {{{"this":"is","a":["test"]}}}
do_execsql_test json102-130b {
SELECT json(jsonb(' { "this" : "is", "a": [ "test" ] } '));
} {{{"this":"is","a":["test"]}}}
do_execsql_test json102-140 {
SELECT json_array(1,2,'3',4);
} {{[1,2,"3",4]}}
do_execsql_test json102-140b {
SELECT json(jsonb_array(1,2,'3',4));
} {{[1,2,"3",4]}}
do_execsql_test json102-150 {
SELECT json_array('[1,2]');
} {{["[1,2]"]}}
do_execsql_test json102-150b {
SELECT json(jsonb_array('[1,2]'));
} {{["[1,2]"]}}
do_execsql_test json102-160 {
SELECT json_array(json_array(1,2));
} {{[[1,2]]}}
do_execsql_test json102-160-2 {
SELECT json_array(jsonb_array(1,2));
} {{[[1,2]]}}
do_execsql_test json102-160-3 {
SELECT json(jsonb_array(json_array(1,2)));
} {{[[1,2]]}}
do_execsql_test json102-160-4 {
SELECT json(jsonb_array(jsonb_array(1,2)));
} {{[[1,2]]}}
do_execsql_test json102-170 {
SELECT json_array(1,null,'3','[4,5]','{"six":7.7}');
} {{[1,null,"3","[4,5]","{\"six\":7.7}"]}}
do_execsql_test json102-170b {
SELECT json(jsonb_array(1,null,'3','[4,5]','{"six":7.7}'));
} {{[1,null,"3","[4,5]","{\"six\":7.7}"]}}
do_execsql_test json102-180 {
SELECT json_array(1,null,'3',json('[4,5]'),json('{"six":7.7}'));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-2 {
SELECT json_array(1,null,'3',jsonb('[4,5]'),json('{"six":7.7}'));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-3 {
SELECT json(jsonb_array(1,null,'3',json('[4,5]'),json('{"six":7.7}')));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-180-4 {
SELECT json(jsonb_array(1,null,'3',jsonb('[4,5]'),jsonb('{"six":7.7}')));
} {{[1,null,"3",[4,5],{"six":7.7}]}}
do_execsql_test json102-190 {
SELECT json_array_length('[1,2,3,4]');
} {{4}}
do_execsql_test json102-190b {
SELECT json_array_length(jsonb('[1,2,3,4]'));
} {{4}}
do_execsql_test json102-191 {
SELECT json_array_length( json_remove('[1,2,3,4]','$[2]') );
} {{3}}
do_execsql_test json102-191b {
SELECT json_array_length( jsonb_remove('[1,2,3,4]','$[2]') );
} {{3}}
do_execsql_test json102-200 {
SELECT json_array_length('[1,2,3,4]', '$');
} {{4}}
do_execsql_test json102-200b {
SELECT json_array_length(jsonb('[1,2,3,4]'), '$');
} {{4}}
do_execsql_test json102-210 {
SELECT json_array_length('[1,2,3,4]', '$[2]');
} {{0}}
do_execsql_test json102-210b {
SELECT json_array_length(jsonb('[1,2,3,4]'), '$[2]');
} {{0}}
do_execsql_test json102-220 {
SELECT json_array_length('{"one":[1,2,3]}');
} {{0}}
do_execsql_test json102-230 {
SELECT json_array_length('{"one":[1,2,3]}', '$.one');
do_execsql_test json102-220 {
SELECT json_array_length('{"one":[1,2,3]}');
} {{0}}
do_execsql_test json102-230b {
SELECT json_array_length(jsonb('{"one":[1,2,3]}'), '$.one');
} {{3}}
do_execsql_test json102-240 {
SELECT json_array_length('{"one":[1,2,3]}', '$.two');
} {{}}
do_execsql_test json102-240b {
SELECT json_array_length(jsonb('{"one":[1,2,3]}'), '$.two');
} {{}}
do_execsql_test json102-250 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$');
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-2 {
SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$');
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-3 {
SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$'));
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-250-4 {
SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$'));
} {{{"a":2,"c":[4,5,{"f":7}]}}}
do_execsql_test json102-260 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c');
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-2 {
SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c');
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-3 {
SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c'));
} {{[4,5,{"f":7}]}}
do_execsql_test json102-260-4 {
SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c'));
} {{[4,5,{"f":7}]}}
do_execsql_test json102-270 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]');
} {{{"f":7}}}
do_execsql_test json102-270-2 {
SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c[2]');
} {{{"f":7}}}
do_execsql_test json102-270-3 {
SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.c[2]'));
} {{{"f":7}}}
do_execsql_test json102-270-4 {
SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]'));
} {{{"f":7}}}
do_execsql_test json102-280 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f');
} {{7}}
do_execsql_test json102-280b {
SELECT jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f');
} {{7}}
do_execsql_test json102-290 {
SELECT json_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a');
} {{[[4,5],2]}}
do_execsql_test json102-290-2 {
SELECT json_extract(jsonb('{"a":2,"c":[4,5],"f":7}'),'$.c','$.a');
} {{[[4,5],2]}}
do_execsql_test json102-290-3 {
SELECT json(jsonb_extract('{"a":2,"c":[4,5],"f":7}','$.c','$.a'));
} {{[[4,5],2]}}
do_execsql_test json102-290-4 {
SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5],"f":7}'),'$.c','$.a'));
} {{[[4,5],2]}}
do_execsql_test json102-300 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x');
} {{}}
do_execsql_test json102-300b {
SELECT jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x');
} {{}}
do_execsql_test json102-310 {
SELECT json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x', '$.a');
} {{[null,2]}}
do_execsql_test json102-310-2 {
SELECT json_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.x', '$.a');
} {{[null,2]}}
do_execsql_test json102-310-3 {
SELECT json(jsonb_extract(jsonb('{"a":2,"c":[4,5,{"f":7}]}'), '$.x', '$.a'));
} {{[null,2]}}
do_execsql_test json102-310-43 {
SELECT json(jsonb_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x', '$.a'));
} {{[null,2]}}
do_execsql_test json102-320 {
SELECT json_insert('{"a":2,"c":4}', '$.a', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-2 {
SELECT json_insert(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-3 {
SELECT json(jsonb_insert('{"a":2,"c":4}', '$.a', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-320-4 {
SELECT json(jsonb_insert(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-330 {
SELECT json_insert('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-2 {
SELECT json_insert(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-3 {
SELECT json(jsonb_insert('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-330-4 {
SELECT json(jsonb_insert(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-340 {
SELECT json_replace('{"a":2,"c":4}', '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-2 {
SELECT json_replace(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-3 {
SELECT json(jsonb_replace('{"a":2,"c":4}', '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-340-4 {
SELECT json(jsonb_replace(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-350 {
SELECT json_replace('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-2 {
SELECT json_replace(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-3 {
SELECT json(jsonb_replace('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-350-4 {
SELECT json(jsonb_replace(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4}}}
do_execsql_test json102-360 {
SELECT json_set('{"a":2,"c":4}', '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-2 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.a', 99);
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-3 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-360-4 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.a', 99));
} {{{"a":99,"c":4}}}
do_execsql_test json102-370 {
SELECT json_set('{"a":2,"c":4}', '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-2 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.e', 99);
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-3 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-370-4 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.e', 99));
} {{{"a":2,"c":4,"e":99}}}
do_execsql_test json102-380 {
SELECT json_set('{"a":2,"c":4}', '$.c', '[97,96]');
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-2 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', '[97,96]');
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-3 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', '[97,96]'));
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-380-4 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', '[97,96]'));
} {{{"a":2,"c":"[97,96]"}}}
do_execsql_test json102-390 {
SELECT json_set('{"a":2,"c":4}', '$.c', json('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-2 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', json('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-3 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', json('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-4 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', json('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-5 {
SELECT json_set('{"a":2,"c":4}', '$.c', jsonb('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-6 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb('[97,96]'));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-7 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', jsonb('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-390-8 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb('[97,96]')));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400 {
SELECT json_set('{"a":2,"c":4}', '$.c', json_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-2 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', json_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-3 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', json_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-4 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', json_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-5 {
SELECT json_set('{"a":2,"c":4}', '$.c', jsonb_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-6 {
SELECT json_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb_array(97,96));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-7 {
SELECT json(jsonb_set('{"a":2,"c":4}', '$.c', jsonb_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-400-8 {
SELECT json(jsonb_set(jsonb('{"a":2,"c":4}'), '$.c', jsonb_array(97,96)));
} {{{"a":2,"c":[97,96]}}}
do_execsql_test json102-410 {
SELECT json_object('a',2,'c',4);
} {{{"a":2,"c":4}}}
do_execsql_test json102-410b {
SELECT json(jsonb_object('a',2,'c',4));
} {{{"a":2,"c":4}}}
do_execsql_test json102-420 {
SELECT json_object('a',2,'c','{e:5}');
} {{{"a":2,"c":"{e:5}"}}}
do_execsql_test json102-420b {
SELECT json(jsonb_object('a',2,'c','{e:5}'));
} {{{"a":2,"c":"{e:5}"}}}
do_execsql_test json102-430 {
SELECT json_object('a',2,'c',json_object('e',5));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-2 {
SELECT json(jsonb_object('a',2,'c',json_object('e',5)));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-3 {
SELECT json_object('a',2,'c',jsonb_object('e',5));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-430-4 {
SELECT json(jsonb_object('a',2,'c',jsonb_object('e',5)));
} {{{"a":2,"c":{"e":5}}}}
do_execsql_test json102-440 {
SELECT json_remove('[0,1,2,3,4]','$[2]');
} {{[0,1,3,4]}}
do_execsql_test json102-440-2 {
SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[2]');
} {{[0,1,3,4]}}
do_execsql_test json102-440-3 {
SELECT json(jsonb_remove('[0,1,2,3,4]','$[2]'));
} {{[0,1,3,4]}}
do_execsql_test json102-440-4 {
SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[2]'));
} {{[0,1,3,4]}}
do_execsql_test json102-450 {
SELECT json_remove('[0,1,2,3,4]','$[2]','$[0]');
} {{[1,3,4]}}
do_execsql_test json102-450-2 {
SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[2]','$[0]');
} {{[1,3,4]}}
do_execsql_test json102-450-3 {
SELECT json(jsonb_remove('[0,1,2,3,4]','$[2]','$[0]'));
} {{[1,3,4]}}
do_execsql_test json102-450-4 {
SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[2]','$[0]'));
} {{[1,3,4]}}
do_execsql_test json102-460 {
SELECT json_remove('[0,1,2,3,4]','$[0]','$[2]');
} {{[1,2,4]}}
do_execsql_test json102-460-2 {
SELECT json_remove(jsonb('[0,1,2,3,4]'),'$[0]','$[2]');
} {{[1,2,4]}}
do_execsql_test json102-460-3 {
SELECT json(jsonb_remove('[0,1,2,3,4]','$[0]','$[2]'));
} {{[1,2,4]}}
do_execsql_test json102-460-4 {
SELECT json(jsonb_remove(jsonb('[0,1,2,3,4]'),'$[0]','$[2]'));
} {{[1,2,4]}}
do_execsql_test json102-470 {
SELECT json_remove('{"x":25,"y":42}');
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-2 {
SELECT json_remove(jsonb('{"x":25,"y":42}'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-3 {
SELECT json(jsonb_remove('{"x":25,"y":42}'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-470-4 {
SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}')));
} {{{"x":25,"y":42}}}
do_execsql_test json102-480 {
SELECT json_remove('{"x":25,"y":42}','$.z');
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-2 {
SELECT json_remove(jsonb('{"x":25,"y":42}'),'$.z');
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-3 {
SELECT json(jsonb_remove('{"x":25,"y":42}','$.z'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-480-4 {
SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$.z'));
} {{{"x":25,"y":42}}}
do_execsql_test json102-490 {
SELECT json_remove('{"x":25,"y":42}','$.y');
} {{{"x":25}}}
do_execsql_test json102-490-2 {
SELECT json_remove(jsonb('{"x":25,"y":42}'),'$.y');
} {{{"x":25}}}
do_execsql_test json102-490-3 {
SELECT json(jsonb_remove('{"x":25,"y":42}','$.y'));
} {{{"x":25}}}
do_execsql_test json102-490-4 {
SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$.y'));
} {{{"x":25}}}
do_execsql_test json102-500 {
SELECT json_remove('{"x":25,"y":42}','$');
} {{}}
do_execsql_test json102-500-2 {
SELECT json_remove(jsonb('{"x":25,"y":42}'),'$');
} {{}}
do_execsql_test json102-500-3 {
SELECT json(jsonb_remove('{"x":25,"y":42}','$'));
} {{}}
do_execsql_test json102-500-4 {
SELECT json(jsonb_remove(jsonb('{"x":25,"y":42}'),'$'));
} {{}}
do_execsql_test json102-510 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}');
} {{object}}
do_execsql_test json102-510b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778');
} {{object}}
do_execsql_test json102-520 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$');
} {{object}}
do_execsql_test json102-520b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$');
} {{object}}
do_execsql_test json102-530 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a');
} {{array}}
do_execsql_test json102-530b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a');
} {{array}}
do_execsql_test json102-540 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]');
} {{integer}}
do_execsql_test json102-540b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[0]');
} {{integer}}
do_execsql_test json102-550 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]');
} {{real}}
do_execsql_test json102-550b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[1]');
} {{real}}
do_execsql_test json102-560 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]');
} {{true}}
do_execsql_test json102-560b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[2]');
} {{true}}
do_execsql_test json102-570 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]');
} {{false}}
do_execsql_test json102-570b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[3]');
} {{false}}
do_execsql_test json102-580 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]');
} {{null}}
do_execsql_test json102-580b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[4]');
} {{null}}
do_execsql_test json102-590 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]');
} {{text}}
do_execsql_test json102-590b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[5]');
} {{text}}
do_execsql_test json102-600 {
SELECT json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]');
} {{}}
do_execsql_test json102-600b {
SELECT json_type(x'cc0f1761cb0b133235332e350102001778','$.a[6]');
} {{}}
do_execsql_test json102-610 {
SELECT json_valid(char(123)||'"x":35'||char(125));
} {{1}}
@@ -183,17 +516,24 @@ do_execsql_test json102-620 {
ifcapable vtab {
do_execsql_test json102-1000 {
CREATE TABLE user(name,phone);
CREATE TABLE user(name,phone,phoneb);
INSERT INTO user(name,phone) VALUES
('Alice','["919-555-2345","804-555-3621"]'),
('Bob','["201-555-8872"]'),
('Cindy','["704-555-9983"]'),
('Dave','["336-555-8421","704-555-4321","803-911-4421"]');
UPDATE user SET phoneb=jsonb(phone);
SELECT DISTINCT user.name
FROM user, json_each(user.phone)
WHERE json_each.value LIKE '704-%'
ORDER BY 1;
} {Cindy Dave}
do_execsql_test json102-1000b {
SELECT DISTINCT user.name
FROM user, json_each(user.phoneb)
WHERE json_each.value LIKE '704-%'
ORDER BY 1;
} {Cindy Dave}
do_execsql_test json102-1010 {
UPDATE user
@@ -253,6 +593,12 @@ do_execsql_test json102-1110 {
WHERE json_tree.type NOT IN ('object','array')
ORDER BY +big.rowid, +json_tree.id
} $correct_answer
do_execsql_test json102-1110b {
SELECT big.rowid, fullkey, value
FROM big, json_tree(jsonb(big.json))
WHERE json_tree.type NOT IN ('object','array')
ORDER BY +big.rowid, +json_tree.id
} $correct_answer
do_execsql_test json102-1120 {
SELECT big.rowid, fullkey, atom
FROM big, json_tree(big.json)
+5 -5
View File
@@ -96,18 +96,18 @@ json_replace_test 80 {'$.b[#-1]','AAA','$.b[#-1]','BBB'} \
do_catchsql_test json105-6.10 {
SELECT json_extract(j, '$.b[#-]') FROM t1;
} {1 {JSON path error near '[#-]'}}
} {1 {bad JSON path: '$.b[#-]'}}
do_catchsql_test json105-6.20 {
SELECT json_extract(j, '$.b[#9]') FROM t1;
} {1 {JSON path error near '[#9]'}}
} {1 {bad JSON path: '$.b[#9]'}}
do_catchsql_test json105-6.30 {
SELECT json_extract(j, '$.b[#+2]') FROM t1;
} {1 {JSON path error near '[#+2]'}}
} {1 {bad JSON path: '$.b[#+2]'}}
do_catchsql_test json105-6.40 {
SELECT json_extract(j, '$.b[#-1') FROM t1;
} {1 {JSON path error near '[#-1'}}
} {1 {bad JSON path: '$.b[#-1'}}
do_catchsql_test json105-6.50 {
SELECT json_extract(j, '$.b[#-1x]') FROM t1;
} {1 {JSON path error near '[#-1x]'}}
} {1 {bad JSON path: '$.b[#-1x]'}}
finish_test
+3 -3
View File
@@ -252,13 +252,13 @@ do_execsql_test 8.11 {
do_execsql_test 9.1 {
WITH c(x) AS (VALUES('{x: +Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
} {Inf {{"x":9e999}}}
do_execsql_test 9.2 {
WITH c(x) AS (VALUES('{x: -Infinity}')) SELECT x->>'x', json(x) FROM c;
} {-Inf {{"x":-9.0e999}}}
} {-Inf {{"x":-9e999}}}
do_execsql_test 9.3 {
WITH c(x) AS (VALUES('{x: Infinity}')) SELECT x->>'x', json(x) FROM c;
} {Inf {{"x":9.0e999}}}
} {Inf {{"x":9e999}}}
do_execsql_test 9.4 {
WITH c(x) AS (VALUES('{x: NaN}')) SELECT x->>'x', json(x) FROM c;
} {{} {{"x":null}}}
+49
View File
@@ -0,0 +1,49 @@
# 2023-11-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.
#
#***********************************************************************
# Test cases for JSONB
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
do_execsql_test jsonb01-1.1 {
CREATE TABLE t1(x JSON BLOB);
INSERT INTO t1 VALUES(jsonb('{a:5,b:{x:10,y:11},c:[1,2,3,4]}'));
}
foreach {id path res} {
1 {$.a} {{{"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
2 {$.b} {{{"a":5,"c":[1,2,3,4]}}}
3 {$.c} {{{"a":5,"b":{"x":10,"y":11}}}}
4 {$.d} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
5 {$.b.x} {{{"a":5,"b":{"y":11},"c":[1,2,3,4]}}}
6 {$.b.y} {{{"a":5,"b":{"x":10},"c":[1,2,3,4]}}}
7 {$.c[0]} {{{"a":5,"b":{"x":10,"y":11},"c":[2,3,4]}}}
8 {$.c[1]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,3,4]}}}
9 {$.c[2]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,4]}}}
10 {$.c[3]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3]}}}
11 {$.c[4]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
12 {$.c[#]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
13 {$.c[#-1]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3]}}}
14 {$.c[#-2]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,4]}}}
15 {$.c[#-3]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,3,4]}}}
16 {$.c[#-4]} {{{"a":5,"b":{"x":10,"y":11},"c":[2,3,4]}}}
17 {$.c[#-5]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
18 {$.c[#-6]} {{{"a":5,"b":{"x":10,"y":11},"c":[1,2,3,4]}}}
} {
do_execsql_test jsonb01-1.2.$id.1 {
SELECT json(jsonb_remove(x,$path)) FROM t1;
} $res
do_execsql_test jsonb01-1.2.$id.2 {
SELECT json_remove(x,$path) FROM t1;
} $res
}
finish_test
-845
View File
@@ -1,845 +0,0 @@
# 2019 August 01
#
# 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 a program that produces scripts (either shell scripts
# or batch files) to implement a particular test that is part of the SQLite
# release testing procedure. For example, to run veryquick.test with a
# specified set of -D compiler switches.
#
# A "configuration" is a set of options passed to [./configure] and [make]
# to build the SQLite library in a particular fashion. A "platform" is a
# list of tests; most platforms are named after the hardware/OS platform
# that the tests will be run on as part of the release procedure. Each
# "test" is a combination of a configuration and a makefile target (e.g.
# "fulltest"). The program may be invoked as follows:
#
set USAGE {
$argv0 script ?-msvc? CONFIGURATION TARGET
Given a configuration and make target, return a bash (or, if -msvc
is specified, batch) script to execute the test. The first argument
passed to the script must be a directory containing SQLite source code.
$argv0 configurations
List available configurations.
$argv0 platforms
List available platforms.
$argv0 tests ?-nodebug? PLATFORM
List tests in a specified platform. If the -nodebug switch is
specified, synthetic debug/ndebug configurations are omitted. Each
test is a combination of a configuration and a makefile target.
}
# Omit comments (text between # and \n) in a long multi-line string.
#
proc strip_comments {in} {
regsub -all {#[^\n]*\n} $in {} out
return $out
}
array set ::Configs [strip_comments {
"Default" {
-O2
--disable-amalgamation --disable-shared
--enable-session
-DSQLITE_ENABLE_RBU
}
"All-Debug" {
--enable-debug --enable-all
}
"All-O0" {
-O0 --enable-all
}
"Sanitize" {
CC=clang -fsanitize=address,undefined
-DSQLITE_ENABLE_STAT4
-DCONFIG_SLOWDOWN_FACTOR=5.0
--enable-debug
--enable-all
}
"Stdcall" {
-DUSE_STDCALL=1
-O2
}
"Have-Not" {
# The "Have-Not" configuration sets all possible -UHAVE_feature options
# in order to verify that the code works even on platforms that lack
# these support services.
-DHAVE_FDATASYNC=0
-DHAVE_GMTIME_R=0
-DHAVE_ISNAN=0
-DHAVE_LOCALTIME_R=0
-DHAVE_LOCALTIME_S=0
-DHAVE_MALLOC_USABLE_SIZE=0
-DHAVE_STRCHRNUL=0
-DHAVE_USLEEP=0
-DHAVE_UTIME=0
}
"Unlock-Notify" {
-O2
-DSQLITE_ENABLE_UNLOCK_NOTIFY
-DSQLITE_THREADSAFE
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
}
"User-Auth" {
-O2
-DSQLITE_USER_AUTHENTICATION=1
}
"Secure-Delete" {
-O2
-DSQLITE_SECURE_DELETE=1
-DSQLITE_SOUNDEX=1
}
"Update-Delete-Limit" {
-O2
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_ENABLE_STMT_SCANSTATUS
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS
-DSQLITE_ENABLE_CURSOR_HINTS
}
"Check-Symbols" {
-DSQLITE_MEMDEBUG=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
-DSQLITE_ENABLE_MEMSYS3=1
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_SECURE_DELETE=1
-DSQLITE_SOUNDEX=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_STMT_SCANSTATUS
--enable-fts5 --enable-session
}
"Debug-One" {
--disable-shared
-O2 -funsigned-char
-DSQLITE_DEBUG=1
-DSQLITE_MEMDEBUG=1
-DSQLITE_MUTEX_NOOP=1
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_MAX_ATTACHED=125
-DSQLITE_MUTATION_TEST
--enable-fts5
}
"Debug-Two" {
-DSQLITE_DEFAULT_MEMSTATUS=0
-DSQLITE_MAX_EXPR_DEPTH=0
--enable-debug
}
"Fast-One" {
-O6
-DSQLITE_ENABLE_FTS4=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_RBU
-DSQLITE_MAX_ATTACHED=125
-DSQLITE_MAX_MMAP_SIZE=12884901888
-DSQLITE_ENABLE_SORTER_MMAP=1
-DLONGDOUBLE_TYPE=double
--enable-session
}
"Device-One" {
-O2
-DSQLITE_DEBUG=1
-DSQLITE_DEFAULT_AUTOVACUUM=1
-DSQLITE_DEFAULT_CACHE_SIZE=64
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32
-DSQLITE_DISABLE_LFS=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_IOTRACE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_MAX_PAGE_SIZE=4096
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_OMIT_PROGRESS_CALLBACK=1
-DSQLITE_OMIT_VIRTUALTABLE=1
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_TEMP_STORE=3
}
"Device-Two" {
-DSQLITE_4_BYTE_ALIGNED_MALLOC=1
-DSQLITE_DEFAULT_AUTOVACUUM=1
-DSQLITE_DEFAULT_CACHE_SIZE=1000
-DSQLITE_DEFAULT_LOCKING_MODE=0
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000
-DSQLITE_DISABLE_LFS=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_MAX_COMPOUND_SELECT=50
-DSQLITE_MAX_PAGE_SIZE=32768
-DSQLITE_OMIT_TRACE=1
-DSQLITE_TEMP_STORE=3
-DSQLITE_THREADSAFE=2
--enable-fts5 --enable-session
}
"Locking-Style" {
-O2
-DSQLITE_ENABLE_LOCKING_STYLE=1
}
"Apple" {
-Os
-DHAVE_GMTIME_R=1
-DHAVE_ISNAN=1
-DHAVE_LOCALTIME_R=1
-DHAVE_PREAD=1
-DHAVE_PWRITE=1
-DHAVE_UTIME=1
-DSQLITE_DEFAULT_CACHE_SIZE=1000
-DSQLITE_DEFAULT_CKPTFULLFSYNC=1
-DSQLITE_DEFAULT_MEMSTATUS=1
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1
-DSQLITE_ENABLE_API_ARMOR=1
-DSQLITE_ENABLE_AUTO_PROFILE=1
-DSQLITE_ENABLE_FLOCKTIMEOUT=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3_TOKENIZER=1
-DSQLITE_ENABLE_PERSIST_WAL=1
-DSQLITE_ENABLE_PURGEABLE_PCACHE=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_SNAPSHOT=1
# -DSQLITE_ENABLE_SQLLOG=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_MAX_LENGTH=2147483645
-DSQLITE_MAX_VARIABLE_NUMBER=500000
# -DSQLITE_MEMDEBUG=1
-DSQLITE_NO_SYNC=1
-DSQLITE_OMIT_AUTORESET=1
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_PREFER_PROXY_LOCKING=1
-DSQLITE_SERIES_CONSTRAINT_VERIFY=1
-DSQLITE_THREADSAFE=2
-DSQLITE_USE_URI=1
-DSQLITE_WRITE_WALFRAME_PREBUFFERED=1
-DUSE_GUARDED_FD=1
-DUSE_PREAD=1
--enable-fts5
}
"Extra-Robustness" {
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_MAX_ATTACHED=62
}
"Devkit" {
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_MAX_ATTACHED=30
-DSQLITE_ENABLE_COLUMN_METADATA
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_FTS5
-DSQLITE_ENABLE_FTS4_PARENTHESIS
-DSQLITE_DISABLE_FTS4_DEFERRED
-DSQLITE_ENABLE_RTREE
--enable-fts5
}
"No-lookaside" {
-DSQLITE_TEST_REALLOC_STRESS=1
-DSQLITE_OMIT_LOOKASIDE=1
}
"Valgrind" {
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_RTREE
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DLONGDOUBLE_TYPE=double
-DCONFIG_SLOWDOWN_FACTOR=8.0
}
"Windows-Memdebug" {
MEMDEBUG=1
DEBUG=3
}
"Windows-Win32Heap" {
WIN32HEAP=1
DEBUG=4
}
# The next group of configurations are used only by the
# Failure-Detection platform. They are all the same, but we need
# different names for them all so that they results appear in separate
# subdirectories.
#
Fail0 {-O0}
Fail2 {-O0}
Fail3 {-O0}
Fail4 {-O0}
FuzzFail1 {-O0}
FuzzFail2 {-O0}
}]
if {$tcl_platform(os)=="Darwin"} {
lappend Configs(Apple) -DSQLITE_ENABLE_LOCKING_STYLE=1
}
array set ::Platforms [strip_comments {
Linux-x86_64 {
"Check-Symbols*" "" checksymbols
"Fast-One" QUICKTEST_INCLUDE=rbu.test "fuzztest test"
"Debug-One" "" "mptest test"
"Debug-Two" "" test
"Have-Not" "" test
"Secure-Delete" "" test
"Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test
"User-Auth" "" tcltest
"Update-Delete-Limit" "" test
"Extra-Robustness" "" test
"Device-Two" "" "threadtest test"
"No-lookaside" "" test
"Devkit" "" test
"Apple" "" test
"Sanitize*" "" test
"Device-One" "" alltest
"Default" "" "threadtest fuzztest alltest"
"Valgrind*" "" valgrindtest
}
Linux-i686 {
"Devkit" "" test
"Have-Not" "" test
"Unlock-Notify" QUICKTEST_INCLUDE=notify2.test test
"Device-One" "" test
"Device-Two" "" test
"Default" "" "threadtest fuzztest alltest"
}
Darwin-i386 {
"Locking-Style" "" "mptest test"
"Have-Not" "" test
"Apple" "" "threadtest fuzztest alltest"
}
Darwin-x86_64 {
"Locking-Style" "" "mptest test"
"Have-Not" "" test
"Apple" "" "threadtest fuzztest alltest"
}
Darwin-arm64 {
"Locking-Style" "" "mptest test"
"Have-Not" "" test
"Apple" "" "threadtest fuzztest alltest"
}
"Windows NT-intel" {
"Stdcall" "" test
"Have-Not" "" test
"Windows-Memdebug*" "" test
"Windows-Win32Heap*" "" test
"Default" "" "mptest fulltestonly"
}
"Windows NT-amd64" {
"Stdcall" "" test
"Have-Not" "" test
"Windows-Memdebug*" "" test
"Windows-Win32Heap*" "" test
"Default" "" "mptest fulltestonly"
}
# The Failure-Detection platform runs various tests that deliberately
# fail. This is used as a test of this script to verify that this script
# correctly identifies failures.
#
Failure-Detection {
Fail0* "TEST_FAILURE=0" test
Sanitize* "TEST_FAILURE=1" test
Fail2* "TEST_FAILURE=2" valgrindtest
Fail3* "TEST_FAILURE=3" valgrindtest
Fail4* "TEST_FAILURE=4" test
FuzzFail1* "TEST_FAILURE=5" test
FuzzFail2* "TEST_FAILURE=5" valgrindtest
}
}]
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# End of configuration section.
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
# Configuration verification: Check that each entry in the list of configs
# specified for each platforms exists.
#
foreach {key value} [array get ::Platforms] {
foreach {v vars t} $value {
if {[string range $v end end]=="*"} {
set v [string range $v 0 end-1]
}
if {0==[info exists ::Configs($v)]} {
puts stderr "No such configuration: \"$v\""
exit -1
}
}
}
proc usage {} {
global argv0
puts stderr [subst $::USAGE]
exit 1
}
proc is_prefix {p str min} {
set n [string length $p]
if {$n<$min} { return 0 }
if {[string range $str 0 [expr $n-1]]!=$p} { return 0 }
return 1
}
proc main_configurations {} {
foreach k [lsort [array names ::Configs]] {
puts $k
}
}
proc main_platforms {} {
foreach k [lsort [array names ::Platforms]] {
puts "\"$k\""
}
}
proc main_script {args} {
set bMsvc 0
set nArg [llength $args]
if {$nArg==3} {
if {![is_prefix [lindex $args 0] -msvc 2]} usage
set bMsvc 1
} elseif {$nArg<2 || $nArg>3} {
usage
}
set config [lindex $args end-1]
set target [lindex $args end]
set opts [list] ;# OPTS value
set cflags [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value
set makeOpts [list] ;# Extra args for [make]
set configOpts [list] ;# Extra args for [configure]
if {$::tcl_platform(platform)=="windows" || $bMsvc} {
lappend opts -DSQLITE_OS_WIN=1
} else {
lappend opts -DSQLITE_OS_UNIX=1
}
# Figure out if this is a synthetic ndebug or debug configuration.
#
set bRemoveDebug 0
if {[string match *-ndebug $config]} {
set bRemoveDebug 1
set config [string range $config 0 end-7]
}
if {[string match *-debug $config]} {
lappend opts -DSQLITE_DEBUG
lappend opts -DSQLITE_EXTRA_IFNULLROW
set config [string range $config 0 end-6]
}
regexp {^(.*)-[0-9]+} $config -> config
# Ensure that the named configuration exists.
#
if {![info exists ::Configs($config)]} {
puts stderr "No such config: $config"
exit 1
}
# Loop through the parameters of the nominated configuration, updating
# $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as
# follows:
#
# 1. If the parameter begins with a "*", discard it.
#
# 2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or
# -DSQLITE_DEBUG=1, discard it
#
# 3. If the parameter begins with "-D", add it to $opts.
#
# 4. If the parameter begins with "--" add it to $configOpts. Unless
# this command is preparing a script for MSVC - then add an
# equivalent to $makeOpts or $opts.
#
# 5. If the parameter begins with "-" add it to $cflags. If in MSVC
# mode and the parameter is an -O<integer> option, instead add
# an OPTIMIZATIONS=<integer> switch to $makeOpts.
#
# 6. If none of the above apply, add the parameter to $makeOpts
#
foreach param $::Configs($config) {
if {[string range $param 0 0]=="*"} continue
if {$bRemoveDebug} {
if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1"
|| $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1"
|| $param=="--enable-debug"
} {
continue
}
}
if {[string range $param 0 1]=="-D"} {
lappend opts $param
continue
}
if {[string range $param 0 1]=="--"} {
if {$bMsvc} {
switch -- $param {
--disable-amalgamation {
lappend makeOpts USE_AMALGAMATION=0
}
--disable-shared {
lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
}
--enable-fts5 {
lappend opts -DSQLITE_ENABLE_FTS5
}
--enable-shared {
lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
}
--enable-session {
lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK
lappend opts -DSQLITE_ENABLE_SESSION
}
default {
error "Cannot translate $param for MSVC"
}
}
} else {
lappend configOpts $param
}
continue
}
if {[string range $param 0 0]=="-"} {
if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} {
lappend makeOpts OPTIMIZATIONS=$level
} else {
lappend cflags $param
}
continue
}
lappend makeOpts $param
}
# Some configurations specify -DHAVE_USLEEP=0. For all others, add
# -DHAVE_USLEEP=1.
#
if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} {
lappend opts -DHAVE_USLEEP=1
}
if {$bMsvc==0} {
puts {set -e}
puts {}
puts {if [ "$#" -ne 1 ] ; then}
puts { echo "Usage: $0 <sqlite-src-dir>" }
puts { exit -1 }
puts {fi }
puts {SRCDIR=$1}
puts {}
puts "TCL=\"[::tcl::pkgconfig get libdir,install]\""
puts "\$SRCDIR/configure --with-tcl=\$TCL $configOpts"
puts {}
puts {OPTS=" -DSQLITE_NO_SYNC=1"}
foreach o $opts {
puts "OPTS=\"\$OPTS $o\""
}
puts {}
puts "CFLAGS=\"$cflags\""
puts {}
puts "make $target \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts"
} else {
puts {set SRCDIR=%1}
set makecmd "nmake /f %SRCDIR%\\Makefile.msc TOP=%SRCDIR% $target "
append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts"
puts "set TMP=%CD%"
puts $makecmd
}
}
proc main_trscript {args} {
set bMsvc 0
set nArg [llength $args]
if {$nArg==3} {
if {![is_prefix [lindex $args 0] -msvc 2]} usage
set bMsvc 1
} elseif {$nArg<2 || $nArg>3} {
usage
}
set config [lindex $args end-1]
set srcdir [lindex $args end]
set opts [list] ;# OPTS value
set cflags [expr {$bMsvc ? "-Zi" : "-g"}] ;# CFLAGS value
set makeOpts [list] ;# Extra args for [make]
set configOpts [list] ;# Extra args for [configure]
if {$::tcl_platform(platform)=="windows" || $bMsvc} {
lappend opts -DSQLITE_OS_WIN=1
} else {
lappend opts -DSQLITE_OS_UNIX=1
}
# Figure out if this is a synthetic ndebug or debug configuration.
#
set bRemoveDebug 0
if {[string match *-ndebug $config]} {
set bRemoveDebug 1
set config [string range $config 0 end-7]
}
if {[string match *-debug $config]} {
lappend opts -DSQLITE_DEBUG
lappend opts -DSQLITE_EXTRA_IFNULLROW
set config [string range $config 0 end-6]
}
regexp {^(.*)-[0-9]+} $config -> config
# Ensure that the named configuration exists.
#
if {![info exists ::Configs($config)]} {
puts stderr "No such config: $config"
exit 1
}
# Loop through the parameters of the nominated configuration, updating
# $opts, $cflags, $makeOpts and $configOpts along the way. Rules are as
# follows:
#
# 1. If the parameter begins with a "*", discard it.
#
# 2. If $bRemoveDebug is set and the parameter is -DSQLITE_DEBUG or
# -DSQLITE_DEBUG=1, discard it
#
# 3. If the parameter begins with "-D", add it to $opts.
#
# 4. If the parameter begins with "--" add it to $configOpts. Unless
# this command is preparing a script for MSVC - then add an
# equivalent to $makeOpts or $opts.
#
# 5. If the parameter begins with "-" add it to $cflags. If in MSVC
# mode and the parameter is an -O<integer> option, instead add
# an OPTIMIZATIONS=<integer> switch to $makeOpts.
#
# 6. If none of the above apply, add the parameter to $makeOpts
#
foreach param $::Configs($config) {
if {[string range $param 0 0]=="*"} continue
if {$bRemoveDebug} {
if {$param=="-DSQLITE_DEBUG" || $param=="-DSQLITE_DEBUG=1"
|| $param=="-DSQLITE_MEMDEBUG" || $param=="-DSQLITE_MEMDEBUG=1"
|| $param=="--enable-debug"
} {
continue
}
}
if {[string range $param 0 1]=="-D"} {
lappend opts $param
continue
}
if {[string range $param 0 1]=="--"} {
if {$bMsvc} {
switch -- $param {
--disable-amalgamation {
lappend makeOpts USE_AMALGAMATION=0
}
--disable-shared {
lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
}
--enable-fts5 {
lappend opts -DSQLITE_ENABLE_FTS5
}
--enable-shared {
lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
}
--enable-session {
lappend opts -DSQLITE_ENABLE_PREUPDATE_HOOK
lappend opts -DSQLITE_ENABLE_SESSION
}
--enable-all {
}
--enable-debug {
# lappend makeOpts OPTIMIZATIONS=0
lappend opts -DSQLITE_DEBUG
}
default {
error "Cannot translate $param for MSVC"
}
}
} else {
lappend configOpts $param
}
continue
}
if {[string range $param 0 0]=="-"} {
if {$bMsvc && [regexp -- {^-O(\d+)$} $param -> level]} {
lappend makeOpts OPTIMIZATIONS=$level
} else {
lappend cflags $param
}
continue
}
lappend makeOpts $param
}
# Some configurations specify -DHAVE_USLEEP=0. For all others, add
# -DHAVE_USLEEP=1.
#
if {[lsearch $opts "-DHAVE_USLEEP=0"]<0} {
lappend opts -DHAVE_USLEEP=1
}
if {$bMsvc==0} {
puts {set -e}
puts {}
puts {if [ "$#" -ne 1 ] ; then}
puts { echo "Usage: $0 <target>" }
puts { exit -1 }
puts {fi }
puts "SRCDIR=\"$srcdir\""
puts {}
puts "TCL=\"[::tcl::pkgconfig get libdir,install]\""
puts {if [ ! -f Makefile ] ; then}
puts " \$SRCDIR/configure --with-tcl=\$TCL $configOpts"
puts {fi}
puts {}
if {[info exists ::env(OPTS)]} {
puts "# From environment variable:"
puts "OPTS=$::env(OPTS)"
puts ""
}
puts {OPTS="$OPTS -DSQLITE_NO_SYNC=1"}
foreach o $opts {
puts "OPTS=\"\$OPTS $o\""
}
puts {}
puts "CFLAGS=\"$cflags\""
puts {}
puts "make \$1 \"CFLAGS=\$CFLAGS\" \"OPTS=\$OPTS\" $makeOpts"
} else {
set srcdir [file nativename [file normalize $srcdir]]
# set srcdir [string map [list "\\" "\\\\"] $srcdir]
puts {set TARGET=%1}
set makecmd "nmake /f $srcdir\\Makefile.msc TOP=\"$srcdir\" %TARGET% "
append makecmd "\"CFLAGS=$cflags\" \"OPTS=$opts\" $makeOpts"
puts "set TMP=%CD%"
puts $makecmd
}
}
proc main_tests {args} {
set bNodebug 0
set nArg [llength $args]
if {$nArg==2} {
if {[is_prefix [lindex $args 0] -nodebug 2]} {
set bNodebug 1
} elseif {[is_prefix [lindex $args 0] -debug 2]} {
set bNodebug 0
} else usage
} elseif {$nArg==0 || $nArg>2} {
usage
}
set p [lindex $args end]
if {![info exists ::Platforms($p)]} {
puts stderr "No such platform: $p"
exit 1
}
set lTest [list]
foreach {config vars target} $::Platforms($p) {
if {[string range $config end end]=="*"} {
set config [string range $config 0 end-1]
} elseif {$bNodebug==0} {
set dtarget test
if {[lsearch $target fuzztest]<0 && [lsearch $target test]<0} {
set dtarget tcltest
}
if {$vars!=""} { set dtarget "$vars $dtarget" }
if {[string first SQLITE_DEBUG $::Configs($config)]>=0
|| [string first --enable-debug $::Configs($config)]>=0
} {
lappend lTest "$config-ndebug \"$dtarget\""
} else {
lappend lTest "$config-debug \"$dtarget\""
}
}
if {[llength $target]==1 && ([string match "*TEST_FAILURE*" $vars] || (
[lsearch $target "valgrindtest"]<0
&& [lsearch $target "alltest"]<0
&& [lsearch $target "fulltestonly"]<0
&& ![string match Sanitize* $config]
))} {
if {$vars!=""} { set target "$vars $target" }
lappend lTest "$config \"$target\""
} else {
set idir -1
foreach t $target {
if {$t=="valgrindtest" || $t=="alltest" || $t=="fulltestonly"
|| [string match Sanitize* $config]
} {
if {$vars!=""} { set t "$vars $t" }
for {set ii 1} {$ii<=4} {incr ii} {
lappend lTest "$config-[incr idir] \"TCLTEST_PART=$ii/4 $t\""
}
} else {
if {$vars!=""} { set t "$vars $t" }
lappend lTest "$config-[incr idir] \"$t\""
}
}
}
}
foreach l $lTest {
puts $l
}
}
if {[llength $argv]==0} { usage }
set cmd [lindex $argv 0]
set n [expr [llength $argv]-1]
if {[string match ${cmd}* configurations] && $n==0} {
main_configurations
} elseif {[string match ${cmd}* script]} {
main_script {*}[lrange $argv 1 end]
} elseif {[string match ${cmd}* trscript]} {
main_trscript {*}[lrange $argv 1 end]
} elseif {[string match ${cmd}* platforms] && $n==0} {
main_platforms
} elseif {[string match ${cmd}* tests]} {
main_tests {*}[lrange $argv 1 end]
} else {
usage
}
+2
View File
@@ -27,6 +27,8 @@ if {[permutation]=="inmemory_journal"} {
return
}
db timeout 1000
do_execsql_test 1.0 {
CREATE TABLE t1(a, b, c);
PRAGMA journal_mode = wal;
+77 -35
View File
@@ -148,6 +148,8 @@ set TRG(cmdline) $argv
set TRG(reporttime) 2000
set TRG(fuzztest) 0 ;# is the fuzztest option present.
set TRG(zipvfs) "" ;# -zipvfs option, if any
set TRG(buildonly) 0 ;# True if --buildonly option
set TRG(dryrun) 0 ;# True if --dryrun option
switch -nocase -glob -- $tcl_platform(os) {
*darwin* {
@@ -425,8 +427,12 @@ for {set ii 0} {$ii < [llength $argv]} {incr ii} {
if {$isLast} { usage }
} elseif {($n>2 && [string match "$a*" --zipvfs]) || $a=="-z"} {
incr ii
set TRG(zipvfs) [lindex $argv $ii]
set TRG(zipvfs) [file normalize [lindex $argv $ii]]
if {$isLast} { usage }
} elseif {($n>2 && [string match "$a*" --buildonly]) || $a=="-b"} {
set TRG(buildonly) 1
} elseif {($n>2 && [string match "$a*" --dryrun]) || $a=="-d"} {
set TRG(dryrun) 1
} else {
usage
}
@@ -752,6 +758,20 @@ proc add_zipvfs_jobs {} {
set ::env(SQLITE_TEST_DIR) $::testdir
}
# Used to add jobs for "mdevtest" and "sdevtest".
#
proc add_devtest_jobs {lBld patternlist} {
global TRG
foreach b $lBld {
set bld [add_build_job $b $TRG(testfixture)]
add_tcl_jobs $bld veryquick $patternlist
if {$patternlist==""} {
add_fuzztest_jobs $b
}
}
}
proc add_jobs_from_cmdline {patternlist} {
global TRG
@@ -775,33 +795,28 @@ proc add_jobs_from_cmdline {patternlist} {
}
mdevtest {
foreach b [list All-O0 All-Debug] {
set bld [add_build_job $b $TRG(testfixture)]
add_tcl_jobs $bld veryquick ""
add_fuzztest_jobs $b
}
add_devtest_jobs {All-O0 All-Debug} [lrange $patternlist 1 end]
}
sdevtest {
foreach b [list All-Sanitize All-Debug] {
set bld [add_build_job $b $TRG(testfixture)]
add_tcl_jobs $bld veryquick ""
add_fuzztest_jobs $b
}
add_devtest_jobs {All-Sanitize All-Debug} [lrange $patternlist 1 end]
}
release {
set patternlist [lrange $patternlist 1 end]
foreach b [trd_builds $TRG(platform)] {
set bld [add_build_job $b $TRG(testfixture)]
foreach c [trd_configs $TRG(platform) $b] {
add_tcl_jobs $bld $c ""
add_tcl_jobs $bld $c $patternlist
}
foreach e [trd_extras $TRG(platform) $b] {
if {$e=="fuzztest"} {
add_fuzztest_jobs $b
} else {
add_make_job $bld $e
if {$patternlist==""} {
foreach e [trd_extras $TRG(platform) $b] {
if {$e=="fuzztest"} {
add_fuzztest_jobs $b
} else {
add_make_job $bld $e
}
}
}
}
@@ -834,6 +849,17 @@ proc make_new_testset {} {
}
proc mark_job_as_finished {jobid output state endtm} {
r_write_db {
trdb eval {
UPDATE jobs
SET output=$output, state=$state, endtime=$endtm
WHERE jobid=$jobid;
UPDATE jobs SET state='ready' WHERE depid=$jobid;
}
}
}
proc script_input_ready {fd iJob jobid} {
global TRG
global O
@@ -868,15 +894,7 @@ proc script_input_ready {fd iJob jobid} {
puts $TRG(log) "### $job(displayname) ${jobtm}ms ($state)"
puts $TRG(log) [string trim $O($iJob)]
r_write_db {
set output $O($iJob)
trdb eval {
UPDATE jobs
SET output=$output, state=$state, endtime=$tm
WHERE jobid=$jobid;
UPDATE jobs SET state='ready' WHERE depid=$jobid;
}
}
mark_job_as_finished $jobid $O($iJob) $state $tm
dirs_freeDir $iJob
launch_some_jobs
@@ -928,16 +946,28 @@ proc launch_another_job {iJob} {
close $fd
}
set pwd [pwd]
cd $dir
set fd [open $TRG(run) w]
puts $fd $job(cmd)
close $fd
set fd [open "|$TRG(runcmd) 2>@1" r]
cd $pwd
if { $TRG(dryrun) } {
fconfigure $fd -blocking false
fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
mark_job_as_finished $job(jobid) "" done 0
dirs_freeDir $iJob
if {$job(build)!=""} {
puts $TRG(log) "(cd $dir ; $job(cmd) )"
} else {
puts $TRG(log) "$job(cmd)"
}
} else {
set pwd [pwd]
cd $dir
set fd [open $TRG(run) w]
puts $fd $job(cmd)
close $fd
set fd [open "|$TRG(runcmd) 2>@1" r]
cd $pwd
fconfigure $fd -blocking false
fileevent $fd readable [list script_input_ready $fd $iJob $job(jobid)]
}
return 1
}
@@ -1035,6 +1065,16 @@ proc run_testset {} {
puts "Test log is $TRG(logname)"
}
# Handle the --buildonly option, if it was specified.
#
proc handle_buildonly {} {
global TRG
if {$TRG(buildonly)} {
r_write_db {
trdb eval { DELETE FROM jobs WHERE displaytype!='bld' }
}
}
}
sqlite3 trdb $TRG(dbname)
trdb timeout $TRG(timeout)
@@ -1043,6 +1083,8 @@ if {$TRG(nJob)>1} {
puts "splitting work across $TRG(nJob) jobs"
}
puts "built testset in [expr $tm/1000]ms.."
handle_buildonly
run_testset
trdb close
#puts [pwd]
+1
View File
@@ -267,6 +267,7 @@ namespace eval trd {
-DSQLITE_ENABLE_PERSIST_WAL=1
-DSQLITE_ENABLE_PURGEABLE_PCACHE=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_SETLK_TIMEOUT=2
-DSQLITE_ENABLE_SNAPSHOT=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_MAX_LENGTH=2147483645
+20 -7
View File
@@ -132,14 +132,27 @@ do_test trace3-4.3 {
list $stmt [expr {$ns >= 0 && $ns <= 9999999}]; # less than 0.010 seconds
} {/^-?\d+ 1$/}
do_test trace3-4.4 {
set ::stmtlist(record) {}
db trace_v2 trace_v2_record 2
execsql {
SELECT a, b FROM t1 ORDER BY a;
set cnt 0
while {1} {
set ::stmtlist(record) {}
db trace_v2 trace_v2_record 2
execsql {
SELECT a, b FROM t1 ORDER BY a;
}
set stmt [lindex [lindex $::stmtlist(record) 0] 0]
set ns [lindex [lindex $::stmtlist(record) 0] 1]
if {$ns<0 || $ns>9999999} { #less than 0.010 seconds
incr cnt
if {$cnt>3} {
set res "time out of bounds. Expected less than 99999999. Got $ns"
break
}
} else {
set res 1
break
}
}
set stmt [lindex [lindex $::stmtlist(record) 0] 0]
set ns [lindex [lindex $::stmtlist(record) 0] 1]
list $stmt [expr {$ns >= 0 && $ns <= 9999999}]; # less than 0.010 seconds
list $stmt $res
} {/^-?\d+ 1$/}
do_test trace3-5.1 {
-987
View File
@@ -1,987 +0,0 @@
# Copyright (c) 2017 D. Richard Hipp
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Simplified BSD License (also
# known as the "2-Clause License" or "FreeBSD License".)
#
# This program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose.
#
#---------------------------------------------------------------------------
#
# Design rules:
#
# (1) All identifiers in the global namespace begin with "wapp"
#
# (2) Indentifiers intended for internal use only begin with "wappInt"
#
package require Tcl 8.6
# Add text to the end of the HTTP reply. No interpretation or transformation
# of the text is performs. The argument should be enclosed within {...}
#
proc wapp {txt} {
global wapp
dict append wapp .reply $txt
}
# Add text to the page under construction. Do no escaping on the text.
#
# Though "unsafe" in general, there are uses for this kind of thing.
# For example, if you want to return the complete, unmodified content of
# a file:
#
# set fd [open content.html rb]
# wapp-unsafe [read $fd]
# close $fd
#
# You could do the same thing using ordinary "wapp" instead of "wapp-unsafe".
# The difference is that wapp-safety-check will complain about the misuse
# of "wapp", but it assumes that the person who write "wapp-unsafe" understands
# the risks.
#
# Though occasionally necessary, the use of this interface should be minimized.
#
proc wapp-unsafe {txt} {
global wapp
dict append wapp .reply $txt
}
# Add text to the end of the reply under construction. The following
# substitutions are made:
#
# %html(...) Escape text for inclusion in HTML
# %url(...) Escape text for use as a URL
# %qp(...) Escape text for use as a URI query parameter
# %string(...) Escape text for use within a JSON string
# %unsafe(...) No transformations of the text
#
# The substitutions above terminate at the first ")" character. If the
# text of the TCL string in ... contains ")" characters itself, use instead:
#
# %html%(...)%
# %url%(...)%
# %qp%(...)%
# %string%(...)%
# %unsafe%(...)%
#
# In other words, use "%(...)%" instead of "(...)" to include the TCL string
# to substitute.
#
# The %unsafe substitution should be avoided whenever possible, obviously.
# In addition to the substitutions above, the text also does backslash
# escapes.
#
# The wapp-trim proc works the same as wapp-subst except that it also removes
# whitespace from the left margin, so that the generated HTML/CSS/Javascript
# does not appear to be indented when delivered to the client web browser.
#
if {$tcl_version>=8.7} {
proc wapp-subst {txt} {
global wapp
regsub -all -command \
{%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
dict append wapp .reply [subst -novariables -nocommand $txt]
}
proc wapp-trim {txt} {
global wapp
regsub -all {\n\s+} [string trim $txt] \n txt
regsub -all -command \
{%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
dict append wapp .reply [subst -novariables -nocommand $txt]
}
proc wappInt-enc {all mode nu1 txt} {
return [uplevel 2 "wappInt-enc-$mode \"$txt\""]
}
} else {
proc wapp-subst {txt} {
global wapp
regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
{[wappInt-enc-\1 "\3"]} txt
dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
}
proc wapp-trim {txt} {
global wapp
regsub -all {\n\s+} [string trim $txt] \n txt
regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
{[wappInt-enc-\1 "\3"]} txt
dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
}
}
# There must be a wappInt-enc-NAME routine for each possible substitution
# in wapp-subst. Thus there are routines for "html", "url", "qp", and "unsafe".
#
# wappInt-enc-html Escape text so that it is safe to use in the
# body of an HTML document.
#
# wappInt-enc-url Escape text so that it is safe to pass as an
# argument to href= and src= attributes in HTML.
#
# wappInt-enc-qp Escape text so that it is safe to use as the
# value of a query parameter in a URL or in
# post data or in a cookie.
#
# wappInt-enc-string Escape ", ', \, and < for using inside of a
# javascript string literal. The < character
# is escaped to prevent "</script>" from causing
# problems in embedded javascript.
#
# wappInt-enc-unsafe Perform no encoding at all. Unsafe.
#
proc wappInt-enc-html {txt} {
return [string map {& &amp; < &lt; > &gt; \" &quot; \\ &#92;} $txt]
}
proc wappInt-enc-unsafe {txt} {
return $txt
}
proc wappInt-enc-url {s} {
if {[regsub -all {[^-{}@~?=#_.:/a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
set s [subst -novar -noback $s]
}
if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
set s [subst -novar -noback $s]
}
return $s
}
proc wappInt-enc-qp {s} {
if {[regsub -all {[^-{}_.a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
set s [subst -novar -noback $s]
}
if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
set s [subst -novar -noback $s]
}
return $s
}
proc wappInt-enc-string {s} {
return [string map {\\ \\\\ \" \\\" ' \\' < \\u003c} $s]
}
# This is a helper routine for wappInt-enc-url and wappInt-enc-qp. It returns
# an appropriate %HH encoding for the single character c. If c is a unicode
# character, then this routine might return multiple bytes: %HH%HH%HH
#
proc wappInt-%HHchar {c} {
if {$c==" "} {return +}
return [regsub -all .. [binary encode hex [encoding convertto utf-8 $c]] {%&}]
}
# Undo the www-url-encoded format.
#
# HT: This code stolen from ncgi.tcl
#
proc wappInt-decode-url {str} {
set str [string map [list + { } "\\" "\\\\" \[ \\\[ \] \\\]] $str]
regsub -all -- \
{%([Ee][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \
$str {[encoding convertfrom utf-8 [binary decode hex \1\2\3]]} str
regsub -all -- \
{%([CDcd][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \
$str {[encoding convertfrom utf-8 [binary decode hex \1\2]]} str
regsub -all -- {%([0-7][A-Fa-f0-9])} $str {\\u00\1} str
return [subst -novar $str]
}
# Reset the document back to an empty string.
#
proc wapp-reset {} {
global wapp
dict set wapp .reply {}
}
# Change the mime-type of the result document.
#
proc wapp-mimetype {x} {
global wapp
dict set wapp .mimetype $x
}
# Change the reply code.
#
proc wapp-reply-code {x} {
global wapp
dict set wapp .reply-code $x
}
# Set a cookie
#
proc wapp-set-cookie {name value} {
global wapp
dict lappend wapp .new-cookies $name $value
}
# Unset a cookie
#
proc wapp-clear-cookie {name} {
wapp-set-cookie $name {}
}
# Add extra entries to the reply header
#
proc wapp-reply-extra {name value} {
global wapp
dict lappend wapp .reply-extra $name $value
}
# Specifies how the web-page under construction should be cached.
# The argument should be one of:
#
# no-cache
# max-age=N (for some integer number of seconds, N)
# private,max-age=N
#
proc wapp-cache-control {x} {
wapp-reply-extra Cache-Control $x
}
# Redirect to a different web page
#
proc wapp-redirect {uri} {
wapp-reply-code {307 Redirect}
wapp-reply-extra Location $uri
}
# Return the value of a wapp parameter
#
proc wapp-param {name {dflt {}}} {
global wapp
if {![dict exists $wapp $name]} {return $dflt}
return [dict get $wapp $name]
}
# Return true if a and only if the wapp parameter $name exists
#
proc wapp-param-exists {name} {
global wapp
return [dict exists $wapp $name]
}
# Set the value of a wapp parameter
#
proc wapp-set-param {name value} {
global wapp
dict set wapp $name $value
}
# Return all parameter names that match the GLOB pattern, or all
# names if the GLOB pattern is omitted.
#
proc wapp-param-list {{glob {*}}} {
global wapp
return [dict keys $wapp $glob]
}
# By default, Wapp does not decode query parameters and POST parameters
# for cross-origin requests. This is a security restriction, designed to
# help prevent cross-site request forgery (CSRF) attacks.
#
# As a consequence of this restriction, URLs for sites generated by Wapp
# that contain query parameters will not work as URLs found in other
# websites. You cannot create a link from a second website into a Wapp
# website if the link contains query planner, by default.
#
# Of course, it is sometimes desirable to allow query parameters on external
# links. For URLs for which this is safe, the application should invoke
# wapp-allow-xorigin-params. This procedure tells Wapp that it is safe to
# go ahead and decode the query parameters even for cross-site requests.
#
# In other words, for Wapp security is the default setting. Individual pages
# need to actively disable the cross-site request security if those pages
# are safe for cross-site access.
#
proc wapp-allow-xorigin-params {} {
global wapp
if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} {
wappInt-decode-query-params
}
}
# Set the content-security-policy.
#
# The default content-security-policy is very strict: "default-src 'self'"
# The default policy prohibits the use of in-line javascript or CSS.
#
# Provide an alternative CSP as the argument. Or use "off" to disable
# the CSP completely.
#
proc wapp-content-security-policy {val} {
global wapp
if {$val=="off"} {
dict unset wapp .csp
} else {
dict set wapp .csp $val
}
}
# Examine the bodys of all procedures in this program looking for
# unsafe calls to various Wapp interfaces. Return a text string
# containing warnings. Return an empty string if all is ok.
#
# This routine is advisory only. It misses some constructs that are
# dangerous and flags others that are safe.
#
proc wapp-safety-check {} {
set res {}
foreach p [info procs] {
set ln 0
foreach x [split [info body $p] \n] {
incr ln
if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail]
&& [string index $tail 0]!="\173"
&& [regexp {[[$]} $tail]
} {
append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n"
}
if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} {
append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n"
}
}
}
return $res
}
# Return a string that descripts the current environment. Applications
# might find this useful for debugging.
#
proc wapp-debug-env {} {
global wapp
set out {}
foreach var [lsort [dict keys $wapp]] {
if {[string index $var 0]=="."} continue
append out "$var = [list [dict get $wapp $var]]\n"
}
append out "\[pwd\] = [list [pwd]]\n"
return $out
}
# Tracing function for each HTTP request. This is overridden by wapp-start
# if tracing is enabled.
#
proc wappInt-trace {} {}
# Start up a listening socket. Arrange to invoke wappInt-new-connection
# for each inbound HTTP connection.
#
# port Listen on this TCP port. 0 means to select a port
# that is not currently in use
#
# wappmode One of "scgi", "remote-scgi", "server", or "local".
#
# fromip If not {}, then reject all requests from IP addresses
# other than $fromip
#
proc wappInt-start-listener {port wappmode fromip} {
if {[string match *scgi $wappmode]} {
set type SCGI
set server [list wappInt-new-connection \
wappInt-scgi-readable $wappmode $fromip]
} else {
set type HTTP
set server [list wappInt-new-connection \
wappInt-http-readable $wappmode $fromip]
}
if {$wappmode=="local" || $wappmode=="scgi"} {
set x [socket -server $server -myaddr 127.0.0.1 $port]
} else {
set x [socket -server $server $port]
}
set coninfo [chan configure $x -sockname]
set port [lindex $coninfo 2]
if {$wappmode=="local"} {
wappInt-start-browser http://127.0.0.1:$port/
} elseif {$fromip!=""} {
puts "Listening for $type requests on TCP port $port from IP $fromip"
} else {
puts "Listening for $type requests on TCP port $port"
}
}
# Start a web-browser and point it at $URL
#
proc wappInt-start-browser {url} {
global tcl_platform
if {$tcl_platform(platform)=="windows"} {
exec cmd /c start $url &
} elseif {$tcl_platform(os)=="Darwin"} {
exec open $url &
} elseif {[catch {exec xdg-open $url}]} {
exec firefox $url &
}
}
# This routine is a "socket -server" callback. The $chan, $ip, and $port
# arguments are added by the socket command.
#
# Arrange to invoke $callback when content is available on the new socket.
# The $callback will process inbound HTTP or SCGI content. Reject the
# request if $fromip is not an empty string and does not match $ip.
#
proc wappInt-new-connection {callback wappmode fromip chan ip port} {
upvar #0 wappInt-$chan W
if {$fromip!="" && ![string match $fromip $ip]} {
close $chan
return
}
set W [dict create REMOTE_ADDR $ip REMOTE_PORT $port WAPP_MODE $wappmode \
.header {}]
fconfigure $chan -blocking 0 -translation binary
fileevent $chan readable [list $callback $chan]
}
# Close an input channel
#
proc wappInt-close-channel {chan} {
if {$chan=="stdout"} {
# This happens after completing a CGI request
exit 0
} else {
unset ::wappInt-$chan
close $chan
}
}
# Process new text received on an inbound HTTP request
#
proc wappInt-http-readable {chan} {
if {[catch [list wappInt-http-readable-unsafe $chan] msg]} {
puts stderr "$msg\n$::errorInfo"
wappInt-close-channel $chan
}
}
proc wappInt-http-readable-unsafe {chan} {
upvar #0 wappInt-$chan W wapp wapp
if {![dict exists $W .toread]} {
# If the .toread key is not set, that means we are still reading
# the header
set line [string trimright [gets $chan]]
set n [string length $line]
if {$n>0} {
if {[dict get $W .header]=="" || [regexp {^\s+} $line]} {
dict append W .header $line
} else {
dict append W .header \n$line
}
if {[string length [dict get $W .header]]>100000} {
error "HTTP request header too big - possible DOS attack"
}
} elseif {$n==0} {
# We have reached the blank line that terminates the header.
global argv0
set a0 [file normalize $argv0]
dict set W SCRIPT_FILENAME $a0
dict set W DOCUMENT_ROOT [file dir $a0]
if {[wappInt-parse-header $chan]} {
catch {close $chan}
return
}
set len 0
if {[dict exists $W CONTENT_LENGTH]} {
set len [dict get $W CONTENT_LENGTH]
}
if {$len>0} {
# Still need to read the query content
dict set W .toread $len
} else {
# There is no query content, so handle the request immediately
set wapp $W
wappInt-handle-request $chan 0
}
}
} else {
# If .toread is set, that means we are reading the query content.
# Continue reading until .toread reaches zero.
set got [read $chan [dict get $W .toread]]
dict append W CONTENT $got
dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
if {[dict get $W .toread]<=0} {
# Handle the request as soon as all the query content is received
set wapp $W
wappInt-handle-request $chan 0
}
}
}
# Decode the HTTP request header.
#
# This routine is always running inside of a [catch], so if
# any problems arise, simply raise an error.
#
proc wappInt-parse-header {chan} {
upvar #0 wappInt-$chan W
set hdr [split [dict get $W .header] \n]
if {$hdr==""} {return 1}
set req [lindex $hdr 0]
dict set W REQUEST_METHOD [set method [lindex $req 0]]
if {[lsearch {GET HEAD POST} $method]<0} {
error "unsupported request method: \"[dict get $W REQUEST_METHOD]\""
}
set uri [lindex $req 1]
set split_uri [split $uri ?]
set uri0 [lindex $split_uri 0]
if {![regexp {^/[-.a-z0-9_/]*$} $uri0]} {
error "invalid request uri: \"$uri0\""
}
dict set W REQUEST_URI $uri0
dict set W PATH_INFO $uri0
set uri1 [lindex $split_uri 1]
dict set W QUERY_STRING $uri1
set n [llength $hdr]
for {set i 1} {$i<$n} {incr i} {
set x [lindex $hdr $i]
if {![regexp {^(.+): +(.*)$} $x all name value]} {
error "invalid header line: \"$x\""
}
set name [string toupper $name]
switch -- $name {
REFERER {set name HTTP_REFERER}
USER-AGENT {set name HTTP_USER_AGENT}
CONTENT-LENGTH {set name CONTENT_LENGTH}
CONTENT-TYPE {set name CONTENT_TYPE}
HOST {set name HTTP_HOST}
COOKIE {set name HTTP_COOKIE}
ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING}
default {set name .hdr:$name}
}
dict set W $name $value
}
return 0
}
# Decode the QUERY_STRING parameters from a GET request or the
# application/x-www-form-urlencoded CONTENT from a POST request.
#
# This routine sets the ".qp" element of the ::wapp dict as a signal
# that query parameters have already been decoded.
#
proc wappInt-decode-query-params {} {
global wapp
dict set wapp .qp 1
if {[dict exists $wapp QUERY_STRING]} {
foreach qterm [split [dict get $wapp QUERY_STRING] &] {
set qsplit [split $qterm =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][a-z0-9]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
}
if {[dict exists $wapp CONTENT_TYPE] && [dict exists $wapp CONTENT]} {
set ctype [dict get $wapp CONTENT_TYPE]
if {$ctype=="application/x-www-form-urlencoded"} {
foreach qterm [split [string trim [dict get $wapp CONTENT]] &] {
set qsplit [split $qterm =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
} elseif {[string match multipart/form-data* $ctype]} {
regexp {^(.*?)\r\n(.*)$} [dict get $wapp CONTENT] all divider body
set ndiv [string length $divider]
while {[string length $body]} {
set idx [string first $divider $body]
set unit [string range $body 0 [expr {$idx-3}]]
set body [string range $body [expr {$idx+$ndiv+2}] end]
if {[regexp {^Content-Disposition: form-data; (.*?)\r\n\r\n(.*)$} \
$unit unit hdr content]} {
if {[regexp {name="(.*)"; filename="(.*)"\r\nContent-Type: (.*?)$}\
$hdr hr name filename mimetype]} {
dict set wapp $name.filename \
[string map [list \\\" \" \\\\ \\] $filename]
dict set wapp $name.mimetype $mimetype
dict set wapp $name.content $content
} elseif {[regexp {name="(.*)"} $hdr hr name]} {
dict set wapp $name $content
}
}
}
}
}
}
# Invoke application-supplied methods to generate a reply to
# a single HTTP request.
#
# This routine always runs within [catch], so handle exceptions by
# invoking [error].
#
proc wappInt-handle-request {chan useCgi} {
global wapp
dict set wapp .reply {}
dict set wapp .mimetype {text/html; charset=utf-8}
dict set wapp .reply-code {200 Ok}
dict set wapp .csp {default-src 'self'}
# Set up additional CGI environment values
#
if {![dict exists $wapp HTTP_HOST]} {
dict set wapp BASE_URL {}
} elseif {[dict exists $wapp HTTPS]} {
dict set wapp BASE_URL https://[dict get $wapp HTTP_HOST]
} else {
dict set wapp BASE_URL http://[dict get $wapp HTTP_HOST]
}
if {![dict exists $wapp REQUEST_URI]} {
dict set wapp REQUEST_URI /
} elseif {[regsub {\?.*} [dict get $wapp REQUEST_URI] {} newR]} {
# Some servers (ex: nginx) append the query parameters to REQUEST_URI.
# These need to be stripped off
dict set wapp REQUEST_URI $newR
}
if {[dict exists $wapp SCRIPT_NAME]} {
dict append wapp BASE_URL [dict get $wapp SCRIPT_NAME]
} else {
dict set wapp SCRIPT_NAME {}
}
if {![dict exists $wapp PATH_INFO]} {
# If PATH_INFO is missing (ex: nginx) then construct it
set URI [dict get $wapp REQUEST_URI]
set skip [string length [dict get $wapp SCRIPT_NAME]]
dict set wapp PATH_INFO [string range $URI $skip end]
}
if {[regexp {^/([^/]+)(.*)$} [dict get $wapp PATH_INFO] all head tail]} {
dict set wapp PATH_HEAD $head
dict set wapp PATH_TAIL [string trimleft $tail /]
} else {
dict set wapp PATH_INFO {}
dict set wapp PATH_HEAD {}
dict set wapp PATH_TAIL {}
}
dict set wapp SELF_URL [dict get $wapp BASE_URL]/[dict get $wapp PATH_HEAD]
# Parse query parameters from the query string, the cookies, and
# POST data
#
if {[dict exists $wapp HTTP_COOKIE]} {
foreach qterm [split [dict get $wapp HTTP_COOKIE] {;}] {
set qsplit [split [string trim $qterm] =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
}
set same_origin 0
if {[dict exists $wapp HTTP_REFERER]} {
set referer [dict get $wapp HTTP_REFERER]
set base [dict get $wapp BASE_URL]
if {$referer==$base || [string match $base/* $referer]} {
set same_origin 1
}
}
dict set wapp SAME_ORIGIN $same_origin
if {$same_origin} {
wappInt-decode-query-params
}
# Invoke the application-defined handler procedure for this page
# request. If an error occurs while running that procedure, generate
# an HTTP reply that contains the error message.
#
wapp-before-dispatch-hook
wappInt-trace
set mname [dict get $wapp PATH_HEAD]
if {[catch {
if {$mname!="" && [llength [info proc wapp-page-$mname]]>0} {
wapp-page-$mname
} else {
wapp-default
}
} msg]} {
if {[wapp-param WAPP_MODE]=="local" || [wapp-param WAPP_MODE]=="server"} {
puts "ERROR: $::errorInfo"
}
wapp-reset
wapp-reply-code "500 Internal Server Error"
wapp-mimetype text/html
wapp-trim {
<h1>Wapp Application Error</h1>
<pre>%html($::errorInfo)</pre>
}
dict unset wapp .new-cookies
}
# Transmit the HTTP reply
#
if {$chan=="stdout"} {
puts $chan "Status: [dict get $wapp .reply-code]\r"
} else {
puts $chan "HTTP/1.1 [dict get $wapp .reply-code]\r"
puts $chan "Server: wapp\r"
puts $chan "Connection: close\r"
}
if {[dict exists $wapp .reply-extra]} {
foreach {name value} [dict get $wapp .reply-extra] {
puts $chan "$name: $value\r"
}
}
if {[dict exists $wapp .csp]} {
puts $chan "Content-Security-Policy: [dict get $wapp .csp]\r"
}
set mimetype [dict get $wapp .mimetype]
puts $chan "Content-Type: $mimetype\r"
if {[dict exists $wapp .new-cookies]} {
foreach {nm val} [dict get $wapp .new-cookies] {
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
if {$val==""} {
puts $chan "Set-Cookie: $nm=; HttpOnly; Path=/; Max-Age=1\r"
} else {
set val [wappInt-enc-url $val]
puts $chan "Set-Cookie: $nm=$val; HttpOnly; Path=/\r"
}
}
}
}
if {[string match text/* $mimetype]} {
set reply [encoding convertto utf-8 [dict get $wapp .reply]]
if {[regexp {\ygzip\y} [wapp-param HTTP_ACCEPT_ENCODING]]} {
catch {
set x [zlib gzip $reply]
set reply $x
puts $chan "Content-Encoding: gzip\r"
}
}
} else {
set reply [dict get $wapp .reply]
}
puts $chan "Content-Length: [string length $reply]\r"
puts $chan \r
puts -nonewline $chan $reply
flush $chan
wappInt-close-channel $chan
}
# This routine runs just prior to request-handler dispatch. The
# default implementation is a no-op, but applications can override
# to do additional transformations or checks.
#
proc wapp-before-dispatch-hook {} {return}
# Process a single CGI request
#
proc wappInt-handle-cgi-request {} {
global wapp env
foreach key {
CONTENT_LENGTH
CONTENT_TYPE
DOCUMENT_ROOT
HTTP_ACCEPT_ENCODING
HTTP_COOKIE
HTTP_HOST
HTTP_REFERER
HTTP_USER_AGENT
HTTPS
PATH_INFO
QUERY_STRING
REMOTE_ADDR
REQUEST_METHOD
REQUEST_URI
REMOTE_USER
SCRIPT_FILENAME
SCRIPT_NAME
SERVER_NAME
SERVER_PORT
SERVER_PROTOCOL
} {
if {[info exists env($key)]} {
dict set wapp $key $env($key)
}
}
set len 0
if {[dict exists $wapp CONTENT_LENGTH]} {
set len [dict get $wapp CONTENT_LENGTH]
}
if {$len>0} {
fconfigure stdin -translation binary
dict set wapp CONTENT [read stdin $len]
}
dict set wapp WAPP_MODE cgi
fconfigure stdout -translation binary
wappInt-handle-request stdout 1
}
# Process new text received on an inbound SCGI request
#
proc wappInt-scgi-readable {chan} {
if {[catch [list wappInt-scgi-readable-unsafe $chan] msg]} {
puts stderr "$msg\n$::errorInfo"
wappInt-close-channel $chan
}
}
proc wappInt-scgi-readable-unsafe {chan} {
upvar #0 wappInt-$chan W wapp wapp
if {![dict exists $W .toread]} {
# If the .toread key is not set, that means we are still reading
# the header.
#
# An SGI header is short. This implementation assumes the entire
# header is available all at once.
#
dict set W .remove_addr [dict get $W REMOTE_ADDR]
set req [read $chan 15]
set n [string length $req]
scan $req %d:%s len hdr
incr len [string length "$len:,"]
append hdr [read $chan [expr {$len-15}]]
foreach {nm val} [split $hdr \000] {
if {$nm==","} break
dict set W $nm $val
}
set len 0
if {[dict exists $W CONTENT_LENGTH]} {
set len [dict get $W CONTENT_LENGTH]
}
if {$len>0} {
# Still need to read the query content
dict set W .toread $len
} else {
# There is no query content, so handle the request immediately
dict set W SERVER_ADDR [dict get $W .remove_addr]
set wapp $W
wappInt-handle-request $chan 0
}
} else {
# If .toread is set, that means we are reading the query content.
# Continue reading until .toread reaches zero.
set got [read $chan [dict get $W .toread]]
dict append W CONTENT $got
dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
if {[dict get $W .toread]<=0} {
# Handle the request as soon as all the query content is received
dict set W SERVER_ADDR [dict get $W .remove_addr]
set wapp $W
wappInt-handle-request $chan 0
}
}
}
# Start up the wapp framework. Parameters are a list passed as the
# single argument.
#
# -server $PORT Listen for HTTP requests on this TCP port $PORT
#
# -local $PORT Listen for HTTP requests on 127.0.0.1:$PORT
#
# -scgi $PORT Listen for SCGI requests on 127.0.0.1:$PORT
#
# -remote-scgi $PORT Listen for SCGI requests on TCP port $PORT
#
# -cgi Handle a single CGI request
#
# With no arguments, the behavior is called "auto". In "auto" mode,
# if the GATEWAY_INTERFACE environment variable indicates CGI, then run
# as CGI. Otherwise, start an HTTP server bound to the loopback address
# only, on an arbitrary TCP port, and automatically launch a web browser
# on that TCP port.
#
# Additional options:
#
# -fromip GLOB Reject any incoming request where the remote
# IP address does not match the GLOB pattern. This
# value defaults to '127.0.0.1' for -local and -scgi.
#
# -nowait Do not wait in the event loop. Return immediately
# after all event handlers are established.
#
# -trace "puts" each request URL as it is handled, for
# debugging
#
# -lint Run wapp-safety-check on the application instead
# of running the application itself
#
# -Dvar=value Set TCL global variable "var" to "value"
#
#
proc wapp-start {arglist} {
global env
set mode auto
set port 0
set nowait 0
set fromip {}
set n [llength $arglist]
for {set i 0} {$i<$n} {incr i} {
set term [lindex $arglist $i]
if {[string match --* $term]} {set term [string range $term 1 end]}
switch -glob -- $term {
-server {
incr i;
set mode "server"
set port [lindex $arglist $i]
}
-local {
incr i;
set mode "local"
set fromip 127.0.0.1
set port [lindex $arglist $i]
}
-scgi {
incr i;
set mode "scgi"
set fromip 127.0.0.1
set port [lindex $arglist $i]
}
-remote-scgi {
incr i;
set mode "remote-scgi"
set port [lindex $arglist $i]
}
-cgi {
set mode "cgi"
}
-fromip {
incr i
set fromip [lindex $arglist $i]
}
-nowait {
set nowait 1
}
-trace {
proc wappInt-trace {} {
set q [wapp-param QUERY_STRING]
set uri [wapp-param BASE_URL][wapp-param PATH_INFO]
if {$q!=""} {append uri ?$q}
puts $uri
}
}
-lint {
set res [wapp-safety-check]
if {$res!=""} {
puts "Potential problems in this code:"
puts $res
exit 1
} else {
exit
}
}
-D*=* {
if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} {
set ::$var $val
}
}
default {
error "unknown option: $term"
}
}
}
if {$mode=="auto"} {
if {[info exists env(GATEWAY_INTERFACE)]
&& [string match CGI/1.* $env(GATEWAY_INTERFACE)]} {
set mode cgi
} else {
set mode local
}
}
if {$mode=="cgi"} {
wappInt-handle-cgi-request
} else {
wappInt-start-listener $port $mode $fromip
if {!$nowait} {
vwait ::forever
}
}
}
# Call this version 1.0
package provide wapp 1.0
-909
View File
@@ -1,909 +0,0 @@
#!/bin/sh
# \
exec wapptclsh "$0" ${1+"$@"}
# package required wapp
source [file join [file dirname [info script]] wapp.tcl]
# Variables set by the "control" form:
#
# G(platform) - User selected platform.
# G(cfgglob) - Glob pattern that all configurations must match
# G(test) - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only".
# G(keep) - Boolean. True to delete no files after each test.
# G(msvc) - Boolean. True to use MSVC as the compiler.
# G(tcl) - Use Tcl from this directory for builds.
# G(jobs) - How many sub-processes to run simultaneously.
#
set G(platform) $::tcl_platform(os)-$::tcl_platform(machine)
set G(cfgglob) *
set G(test) Normal
set G(keep) 1
set G(msvc) 0
set G(tcl) [::tcl::pkgconfig get libdir,install]
set G(jobs) 3
set G(debug) 0
set G(noui) 0
set G(stdout) 0
proc wapptest_init {} {
global G
set lSave [list platform test keep msvc tcl jobs debug noui stdout cfgglob]
foreach k $lSave { set A($k) $G($k) }
array unset G
foreach k $lSave { set G($k) $A($k) }
# The root of the SQLite source tree.
set G(srcdir) [file dirname [file dirname [info script]]]
set G(sqlite_version) "unknown"
# Either "config", "running" or "stopped":
set G(state) "config"
set G(hostname) "(unknown host)"
catch { set G(hostname) [exec hostname] }
set G(host) $G(hostname)
append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)"
append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)"
}
proc wapptest_run {} {
global G
set_test_array
set G(state) "running"
wapptest_openlog
wapptest_output "Running the following for $G(platform). $G(jobs) jobs."
foreach t $G(test_array) {
set config [dict get $t config]
set target [dict get $t target]
wapptest_output [format " %-25s%s" $config $target]
}
wapptest_output [string repeat * 70]
}
proc releasetest_data {args} {
global G
set rtd [file join $G(srcdir) test releasetest_data.tcl]
set fd [open "|[info nameofexecutable] $rtd $args" r+]
set ret [read $fd]
close $fd
return $ret
}
# Generate the text for the box at the top of the UI. The current SQLite
# version, according to fossil, along with a warning if there are
# uncommitted changes in the checkout.
#
proc generate_fossil_info {} {
global G
set pwd [pwd]
cd $G(srcdir)
set rc [catch {
set r1 [exec fossil info]
set r2 [exec fossil changes]
}]
cd $pwd
if {$rc} return
foreach line [split $r1 "\n"] {
if {[regexp {^checkout: *(.*)$} $line -> co]} {
wapp-trim { <br> %html($co) }
}
}
if {[string trim $r2]!=""} {
wapp-trim {
<br><span class=warning>
WARNING: Uncommitted changes in checkout
</span>
}
}
}
# If the application is in "config" state, set the contents of the
# ::G(test_array) global to reflect the tests that will be run. If the
# app is in some other state ("running" or "stopped"), this command
# is a no-op.
#
proc set_test_array {} {
global G
if { $G(state)=="config" } {
set G(test_array) [list]
set debug "-debug"
if {$G(debug)==0} { set debug "-nodebug"}
foreach {config target} [releasetest_data tests $debug $G(platform)] {
# All configuration names must match $g(cfgglob), which defaults to *
#
if {![string match -nocase $G(cfgglob) $config]} continue
# If using MSVC, do not run sanitize or valgrind tests. Or the
# checksymbols test.
if {$G(msvc) && (
"Sanitize" == $config
|| "checksymbols" in $target
|| "valgrindtest" in $target
)} {
continue
}
# If the test mode is not "Normal", override the target.
#
if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} {
switch -- $G(test) {
Veryquick { set target quicktest }
Smoketest { set target smoketest }
Build-Only {
set target testfixture
if {$::tcl_platform(platform)=="windows"} {
set target testfixture.exe
}
}
}
}
lappend G(test_array) [dict create config $config target $target]
}
}
}
proc count_tests_and_errors {name logfile} {
global G
set fd [open $logfile rb]
set seen 0
while {![eof $fd]} {
set line [gets $fd]
if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
incr G(test.$name.nError) $nerr
incr G(test.$name.nTest) $ntest
set seen 1
if {$nerr>0} {
set G(test.$name.errmsg) $line
}
}
if {[regexp {runtime error: +(.*)} $line all msg]} {
# skip over "value is outside range" errors
if {[regexp {.* is outside the range of representable} $line]} {
# noop
} else {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $msg
}
}
}
if {[regexp {fatal error +(.*)} $line all msg]} {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $msg
}
}
if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $all
}
}
if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
set v [string range $line 9 end]
if {$G(sqlite_version) eq "unknown"} {
set G(sqlite_version) $v
} elseif {$G(sqlite_version) ne $v} {
set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}"
}
}
}
close $fd
if {$G(test) == "Build-Only"} {
incr G(test.$name.nTest)
if {$G(test.$name.nError)>0} {
set errmsg "Build failed"
}
} elseif {!$seen} {
set G(test.$name.errmsg) "Test did not complete"
if {[file readable core]} {
append G(test.$name.errmsg) " - core file exists"
}
}
}
proc wapptest_output {str} {
global G
if {$G(stdout)} { puts $str }
if {[info exists G(log)]} {
puts $G(log) $str
flush $G(log)
}
}
proc wapptest_openlog {} {
global G
set G(log) [open wapptest-out.txt w+]
}
proc wapptest_closelog {} {
global G
close $G(log)
unset G(log)
}
proc format_seconds {seconds} {
set min [format %.2d [expr ($seconds / 60) % 60]]
set hr [format %.2d [expr $seconds / 3600]]
set sec [format %.2d [expr $seconds % 60]]
return "$hr:$min:$sec"
}
# This command is invoked once a slave process has finished running its
# tests, successfully or otherwise. Parameter $name is the name of the
# test, $rc the exit code returned by the slave process.
#
proc slave_test_done {name rc} {
global G
set G(test.$name.done) [clock seconds]
set G(test.$name.nError) 0
set G(test.$name.nTest) 0
set G(test.$name.errmsg) ""
if {$rc} {
incr G(test.$name.nError)
}
if {[file exists $G(test.$name.log)]} {
count_tests_and_errors $name $G(test.$name.log)
}
# If the "keep files" checkbox is clear, delete all files except for
# the executables and test logs. And any core file that is present.
if {$G(keep)==0} {
set keeplist {
testfixture testfixture.exe
sqlite3 sqlite3.exe
test.log test-out.txt
core
wapptest_make.sh
wapptest_configure.sh
wapptest_run.tcl
}
foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] {
set t [file tail $f]
if {[lsearch $keeplist $t]<0} {
catch { file delete -force $f }
}
}
}
# Format a message regarding the success or failure of hte test.
set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]]
set res "OK"
if {$G(test.$name.nError)} { set res "FAILED" }
set dots [string repeat . [expr 60 - [string length $name]]]
set msg "$name $dots $res ($t)"
wapptest_output $msg
if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} {
wapptest_output " $G(test.$name.errmsg)"
}
}
# This is a fileevent callback invoked each time a file-descriptor that
# connects this process to a slave process is readable.
#
proc slave_fileevent {name} {
global G
set fd $G(test.$name.channel)
if {[eof $fd]} {
fconfigure $fd -blocking 1
set rc [catch { close $fd }]
unset G(test.$name.channel)
slave_test_done $name $rc
} else {
set line [gets $fd]
if {[string trim $line] != ""} { puts "Trace : $name - \"$line\"" }
}
do_some_stuff
}
# Return the contents of the "slave script" - the script run by slave
# processes to actually perform the test. All it does is execute the
# test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat).
#
proc wapptest_slave_script {} {
global G
if {$G(msvc)==0} {
set dir [file join .. $G(srcdir)]
set res [subst -nocommands {
set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ]
exit [set rc]
}]
} else {
set dir [file nativename [file normalize $G(srcdir)]]
set dir [string map [list "\\" "\\\\"] $dir]
set res [subst -nocommands {
set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ]
exit [set rc]
}]
}
set res
}
# Launch a slave process to run a test.
#
proc slave_launch {name target dir} {
global G
catch { file mkdir $dir } msg
foreach f [glob -nocomplain [file join $dir *]] {
catch { file delete -force $f }
}
set G(test.$name.dir) $dir
# Write the test command to wapptest_cmd.sh|bat.
#
set ext sh
if {$G(msvc)} { set ext bat }
set fd1 [open [file join $dir wapptest_cmd.$ext] w]
if {$G(msvc)} {
puts $fd1 [releasetest_data script -msvc $name $target]
} else {
puts $fd1 [releasetest_data script $name $target]
}
close $fd1
# Write the wapptest_run.tcl script to the test directory. To run the
# commands in the other two files.
#
set fd3 [open [file join $dir wapptest_run.tcl] w]
puts $fd3 [wapptest_slave_script]
close $fd3
set pwd [pwd]
cd $dir
set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+]
cd $pwd
set G(test.$name.channel) $fd
fconfigure $fd -blocking 0
fileevent $fd readable [list slave_fileevent $name]
}
proc do_some_stuff {} {
global G
# Count the number of running jobs. A running job has an entry named
# "channel" in its dictionary.
set nRunning 0
set bFinished 1
foreach j $G(test_array) {
set name [dict get $j config]
if { [info exists G(test.$name.channel)]} { incr nRunning }
if {![info exists G(test.$name.done)]} { set bFinished 0 }
}
if {$bFinished} {
set nError 0
set nTest 0
set nConfig 0
foreach j $G(test_array) {
set name [dict get $j config]
incr nError $G(test.$name.nError)
incr nTest $G(test.$name.nTest)
incr nConfig
}
set G(result) "$nError errors from $nTest tests in $nConfig configurations."
wapptest_output [string repeat * 70]
wapptest_output $G(result)
catch {
append G(result) " SQLite version $G(sqlite_version)"
wapptest_output " SQLite version $G(sqlite_version)"
}
set G(state) "stopped"
wapptest_closelog
if {$G(noui)} { exit 0 }
} else {
set nLaunch [expr $G(jobs) - $nRunning]
foreach j $G(test_array) {
if {$nLaunch<=0} break
set name [dict get $j config]
if { ![info exists G(test.$name.channel)]
&& ![info exists G(test.$name.done)]
} {
set target [dict get $j target]
set dir [string tolower [string map {" " _ "-" _} $name]]
set G(test.$name.start) [clock seconds]
set G(test.$name.log) [file join $dir test.log]
slave_launch $name $target $dir
incr nLaunch -1
}
}
}
}
proc generate_select_widget {label id lOpt opt} {
wapp-trim {
<label> %string($label) </label>
<select id=%string($id) name=%string($id)>
}
foreach o $lOpt {
set selected ""
if {$o==$opt} { set selected " selected=1" }
wapp-subst "<option $selected>$o</option>"
}
wapp-trim { </select> }
}
proc generate_main_page {{extra {}}} {
global G
set_test_array
set hostname $G(hostname)
wapp-trim {
<html>
<head>
<title> %html($hostname): wapptest.tcl </title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
}
set host $G(host)
wapp-trim {
<div class="border">%string($host)
}
generate_fossil_info
wapp-trim {
</div>
<div class="border" id=controls>
<form action="control" method="post" name="control">
}
# Build the "platform" select widget.
set lOpt [releasetest_data platforms]
generate_select_widget Platform control_platform $lOpt $G(platform)
# Build the "test" select widget.
set lOpt [list Normal Veryquick Smoketest Build-Only]
generate_select_widget Test control_test $lOpt $G(test)
# Build the "jobs" select widget. Options are 1 to 8.
generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8 12 16} $G(jobs)
switch $G(state) {
config {
set txt "Run Tests!"
set id control_run
}
running {
set txt "STOP Tests!"
set id control_stop
}
stopped {
set txt "Reset!"
set id control_reset
}
}
wapp-trim {
<div class=right>
<input id=%string($id) name=%string($id) type=submit value="%string($txt)">
</input>
</div>
}
wapp-trim {
<br><br>
<label> Tcl: </label>
<input id="control_tcl" name="control_tcl"></input>
<label> Keep files: </label>
<input id="control_keep" name="control_keep" type=checkbox value=1>
</input>
<label> Use MSVC: </label>
<input id="control_msvc" name="control_msvc" type=checkbox value=1>
<label> Debug tests: </label>
<input id="control_debug" name="control_debug" type=checkbox value=1>
</input>
}
wapp-trim {
</form>
}
wapp-trim {
</div>
<div id=tests>
}
wapp-page-tests
set script "script/$G(state).js"
wapp-trim {
</div>
<script src=%string($script)></script>
</body>
</html>
}
}
proc wapp-default {} {
generate_main_page
}
proc wapp-page-tests {} {
global G
wapp-trim { <table class="border" width=100%> }
foreach t $G(test_array) {
set config [dict get $t config]
set target [dict get $t target]
set class "testwait"
set seconds ""
if {[info exists G(test.$config.log)]} {
if {[info exists G(test.$config.channel)]} {
set class "testrunning"
set seconds [expr [clock seconds] - $G(test.$config.start)]
} elseif {[info exists G(test.$config.done)]} {
if {$G(test.$config.nError)>0} {
set class "testfail"
} else {
set class "testdone"
}
set seconds [expr $G(test.$config.done) - $G(test.$config.start)]
}
set seconds [format_seconds $seconds]
}
wapp-trim {
<tr class=%string($class)>
<td class="nowrap"> %html($config)
<td class="padleft nowrap"> %html($target)
<td class="padleft nowrap"> %html($seconds)
<td class="padleft nowrap">
}
if {[info exists G(test.$config.log)]} {
set log $G(test.$config.log)
set uri "log/$log"
wapp-trim {
<a href=%url($uri)> %html($log) </a>
}
}
if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} {
set errmsg $G(test.$config.errmsg)
wapp-trim {
<tr class=testfail>
<td> <td class="padleft" colspan=3> %html($errmsg)
}
}
}
wapp-trim { </table> }
if {[info exists G(result)]} {
set res $G(result)
wapp-trim {
<div class=border id=result> %string($res) </div>
}
}
}
# URI: /control
#
# Whenever the form at the top of the application page is submitted, it
# is submitted here.
#
proc wapp-page-control {} {
global G
if {$::G(state)=="config"} {
set lControls [list platform test tcl jobs keep msvc debug]
set G(msvc) 0
set G(keep) 0
set G(debug) 0
} else {
set lControls [list jobs]
}
foreach v $lControls {
if {[wapp-param-exists control_$v]} {
set G($v) [wapp-param control_$v]
}
}
if {[wapp-param-exists control_run]} {
# This is a "run test" command.
wapptest_run
}
if {[wapp-param-exists control_stop]} {
# A "STOP tests" command.
set G(state) "stopped"
set G(result) "Test halted by user"
foreach j $G(test_array) {
set name [dict get $j config]
if { [info exists G(test.$name.channel)] } {
close $G(test.$name.channel)
unset G(test.$name.channel)
slave_test_done $name 1
}
}
wapptest_closelog
}
if {[wapp-param-exists control_reset]} {
# A "reset app" command.
set G(state) "config"
wapptest_init
}
if {$::G(state) == "running"} {
do_some_stuff
}
wapp-redirect /
}
# URI: /style.css
#
# Return the stylesheet for the application main page.
#
proc wapp-page-style.css {} {
wapp-subst {
/* The boxes with black borders use this class */
.border {
border: 3px groove #444444;
padding: 1em;
margin-top: 1em;
margin-bottom: 1em;
}
/* Float to the right (used for the Run/Stop/Reset button) */
.right { float: right; }
/* Style for the large red warning at the top of the page */
.warning {
color: red;
font-weight: bold;
}
/* Styles used by cells in the test table */
.padleft { padding-left: 5ex; }
.nowrap { white-space: nowrap; }
/* Styles for individual tests, depending on the outcome */
.testwait { }
.testrunning { color: blue }
.testdone { color: green }
.testfail { color: red }
}
}
# URI: /script/${state}.js
#
# The last part of this URI is always "config.js", "running.js" or
# "stopped.js", depending on the state of the application. It returns
# the javascript part of the front-end for the requested state to the
# browser.
#
proc wapp-page-script {} {
regexp {[^/]*$} [wapp-param REQUEST_URI] script
set tcl $::G(tcl)
set keep $::G(keep)
set msvc $::G(msvc)
set debug $::G(debug)
wapp-subst {
var lElem = \["control_platform", "control_test", "control_msvc",
"control_jobs", "control_debug"
\];
lElem.forEach(function(e) {
var elem = document.getElementById(e);
elem.addEventListener("change", function() { control.submit() } );
})
elem = document.getElementById("control_tcl");
elem.value = "%string($tcl)"
elem = document.getElementById("control_keep");
elem.checked = %string($keep);
elem = document.getElementById("control_msvc");
elem.checked = %string($msvc);
elem = document.getElementById("control_debug");
elem.checked = %string($debug);
}
if {$script != "config.js"} {
wapp-subst {
var lElem = \["control_platform", "control_test",
"control_tcl", "control_keep", "control_msvc",
"control_debug"
\];
lElem.forEach(function(e) {
var elem = document.getElementById(e);
elem.disabled = true;
})
}
}
if {$script == "running.js"} {
wapp-subst {
function reload_tests() {
fetch('tests')
.then( data => data.text() )
.then( data => {
document.getElementById("tests").innerHTML = data;
})
.then( data => {
if( document.getElementById("result") ){
document.location = document.location;
} else {
setTimeout(reload_tests, 1000)
}
});
}
setTimeout(reload_tests, 1000)
}
}
}
# URI: /env
#
# This is for debugging only. Serves no other purpose.
#
proc wapp-page-env {} {
wapp-allow-xorigin-params
wapp-trim {
<h1>Wapp Environment</h1>\n<pre>
<pre>%html([wapp-debug-env])</pre>
}
}
# URI: /log/dirname/test.log
#
# This URI reads file "dirname/test.log" from disk, wraps it in a <pre>
# block, and returns it to the browser. Use for viewing log files.
#
proc wapp-page-log {} {
set log [string range [wapp-param REQUEST_URI] 5 end]
set fd [open $log]
set data [read $fd]
close $fd
wapp-trim {
<pre>
%html($data)
</pre>
}
}
# Print out a usage message. Then do [exit 1].
#
proc wapptest_usage {} {
puts stderr {
This Tcl script is used to test various configurations of SQLite. By
default it uses "wapp" to provide an interactive interface. Supported
command line options (all optional) are:
--platform PLATFORM (which tests to run)
--config GLOB (only run configurations matching GLOB)
--smoketest (run "make smoketest" only)
--veryquick (run veryquick.test only)
--buildonly (build executables, do not run tests)
--jobs N (number of concurrent jobs)
--tcl DIR (where to find tclConfig.sh)
--deletefiles (delete extra files after each test)
--msvc (Use MS Visual C)
--debug (Also run [n]debugging versions of tests)
--noui (do not use wapp)
}
exit 1
}
# Sort command line arguments into two groups: those that belong to wapp,
# and those that belong to the application.
set WAPPARG(-server) 1
set WAPPARG(-local) 1
set WAPPARG(-scgi) 1
set WAPPARG(-remote-scgi) 1
set WAPPARG(-fromip) 1
set WAPPARG(-nowait) 0
set WAPPARG(-cgi) 0
set lWappArg [list]
set lTestArg [list]
for {set i 0} {$i < [llength $argv]} {incr i} {
set arg [lindex $argv $i]
if {[string range $arg 0 1]=="--"} {
set arg [string range $arg 1 end]
}
if {[info exists WAPPARG($arg)]} {
lappend lWappArg $arg
if {$WAPPARG($arg)} {
incr i
lappend lWappArg [lindex $argv $i]
}
} else {
lappend lTestArg $arg
}
}
wapptest_init
for {set i 0} {$i < [llength $lTestArg]} {incr i} {
set opt [lindex $lTestArg $i]
if {[string range $opt 0 1]=="--"} {
set opt [string range $opt 1 end]
}
switch -- $opt {
-platform {
if {$i==[llength $lTestArg]-1} { wapptest_usage }
incr i
set arg [lindex $lTestArg $i]
set lPlatform [releasetest_data platforms]
if {[lsearch $lPlatform $arg]<0} {
puts stderr "No such platform: $arg. Platforms are: $lPlatform"
exit -1
}
set G(platform) $arg
}
-smoketest { set G(test) Smoketest }
-veryquick { set G(test) Veryquick }
-buildonly { set G(test) Build-Only }
-jobs {
if {$i==[llength $lTestArg]-1} { wapptest_usage }
incr i
set G(jobs) [lindex $lTestArg $i]
}
-tcl {
if {$i==[llength $lTestArg]-1} { wapptest_usage }
incr i
set G(tcl) [lindex $lTestArg $i]
}
-deletefiles {
set G(keep) 0
}
-msvc {
set G(msvc) 1
}
-debug {
set G(debug) 1
}
-noui {
set G(noui) 1
set G(stdout) 1
}
-config {
if {$i==[llength $lTestArg]-1} { wapptest_usage }
incr i
set G(cfgglob) [lindex $lTestArg $i]
}
-stdout {
set G(stdout) 1
}
default {
puts stderr "Unrecognized option: [lindex $lTestArg $i]"
wapptest_usage
}
}
}
if {$G(noui)==0} {
wapp-start $lWappArg
} else {
wapptest_run
do_some_stuff
vwait forever
}
+1 -1
View File
@@ -1881,7 +1881,7 @@ do_catchsql_test 57.3 {
SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
)
FROM t3;
} {1 {misuse of aggregate: sum()}}
} {0 5}
# 2020-06-06 ticket 1f6f353b684fc708
reset_db
+14 -1
View File
@@ -36,6 +36,17 @@ set TCLSH [info nameofexe]
#
set NERR 0
######################### configure ###########################################
set conf [readfile $ROOT/configure]
set vers [readfile $ROOT/VERSION]
if {[string first $vers $conf]<=0} {
puts "ERROR: ./configure does not agree with ./VERSION"
puts "...... Fix: run autoconf"
incr NERR
}
unset conf
######################### autoconf/tea/configure.ac ###########################
set confac [readfile $ROOT/autoconf/tea/configure.ac]
@@ -45,9 +56,11 @@ append pattern [string trim $vers]
append pattern {])}
if {[string first $pattern $confac]<=0} {
puts "ERROR: ./autoconf/tea/configure.ac does not agree with ./VERSION"
puts "...... Fix: manually edit ./autoconf/tea/configure.ac to"
puts "...... Fix: manually edit ./autoconf/tea/configure.ac and put the"
puts "...... correct version number in AC_INIT()"
incr NERR
}
unset confac
######################### autoconf/Makefile.msc ###############################