Compare commits

..

102 Commits

Author SHA1 Message Date
dan 11546779b7 Merge latest trunk changes into this branch.
FossilOrigin-Name: d5b597b52a1213cdf382d96f4df3535727be0852b25bafd12bbef54da946c5f2
2017-12-16 19:16:24 +00:00
drh 468c649331 Add unnecessary initializations to some local variables in the rtree module
to suppress false-positive compiler warnings coming out of MSVC.

FossilOrigin-Name: 64487d658cb3b6c8c67f1e198c70813c963de52599f3ea974bdc2aa432e74de9
2017-12-16 04:37:15 +00:00
dan 2c44e370f1 Enhance the "swarmvtab" extension. See header comments in ext/misc/unionvtab.c
for details.

FossilOrigin-Name: 01c173651ab22b7b0c139eded6f2ad8504efd09088df8ae6a3471230ebf2306f
2017-12-15 20:21:17 +00:00
drh 087316ceec In the LEMON parser generator, provide reduce actions with access to the
lookahead token.

FossilOrigin-Name: 42af190f4f86ad60de02800054010fafd484ac86ca41e2a13799b2e583eea98c
2017-12-15 12:22:21 +00:00
drh 84a6c85c64 In valueFromExpr() only generate a OOM fault if there have been now prior
faults.

FossilOrigin-Name: 3765aaf712998af5ffb6bc680a0c1419f2b5deb47ecbc1835ba5879127c4dbe3
2017-12-13 23:47:55 +00:00
mistachkin 3384ccb8bb Add support for the 'lsm1.c' target in the MSVC makefile.
FossilOrigin-Name: 6de21deac469ab25378656f6f58115a92f5892428c6f2f3545c9bafac37e4a41
2017-12-13 22:42:55 +00:00
drh 258dfe48cf An improved way of generating the SQLITE_READONLY_DIRECTORY error.
The error message submitted to sqlite3_log() is still correct this way.

FossilOrigin-Name: 1c0aa919ee429cd194820ec9c54084563f39e63fd399b23f859fc6703b429b15
2017-12-13 20:35:34 +00:00
drh a803a2cd98 New result code SQLITE_READONLY_DIRECTORY is returned when an attempt is
made to write on a database file that is in a read-only directory and hence
the journal file could not be created.  This situation formerly returned
SQLITE_CANTOPEN, which less helpful.

FossilOrigin-Name: 3ec73c38f878d73d278fce99ba10c708dcc475835774f1e17769ff7315be6d7c
2017-12-13 20:02:29 +00:00
drh 472e41ea16 Correctly invalidate a column cache line when it is overwritten with NULL.
Fix for ticket [123c9ba32130a6c9d432].

FossilOrigin-Name: 65754dc3b830ef9482655d2e93c2cd4acaa7a8715a58d8309955d04378541f89
2017-12-13 18:01:52 +00:00
dan 34aebb88da Change some LSM code internal typenames from "Blob" and "Pgno" to "LsmBlob"
and "LsmPgno". This allows the LSM code to be compiled as a single unit with
sqlite3.c.

FossilOrigin-Name: 30bf38d589adf0b2eb613e184ffb03ed7e625736cb04fd5c341328f72bc5ef4d
2017-12-13 15:32:33 +00:00
dan 62128540ef Add script to amalgamate all LSM files into "lsm1.c".
FossilOrigin-Name: e32b69d73062e233b0ac853611d10b24546a346a603289ab0e339a3604ae2af4
2017-12-13 14:22:48 +00:00
drh 37874b5f74 Minor enhancement to two assert() statements in the default VFSes.
FossilOrigin-Name: 9cede8a83ca4cd88d504050115e1e89e7b3d3cd3cb2ffb5b8961e311a23ff5e2
2017-12-13 10:11:09 +00:00
dan 2e6ca188c4 Fix a buffer overwrite in fts5 that could occur when processing a prefix
query.

FossilOrigin-Name: 92fc146bc2b781e7e2d7138b00e5ea649c6fee1c2b8449420460a1b3e5c9661b
2017-12-11 17:20:37 +00:00
drh 62be1fab6a Fix a harmless API signature mismatch in the unix VFS.
FossilOrigin-Name: bab9de7fdda20a724f7c21ec2c25b488ece08b685f1e4fd15c9e73b6b4a0133a
2017-12-09 01:02:33 +00:00
drh 7e8515d8be The query planner tries to avoids using indexes that use unknown collating
functions.

FossilOrigin-Name: 02013fc120bf71a8be3550c696a588af8c92f2209f8e5db530624878ddc8aa7e
2017-12-08 19:37:04 +00:00
dan 21540ae479 Add compile time switch SQLITE_ENABLE_ICU_COLLATIONS. For enabling ICU
collations without also enabling the tokenizer, the LIKE operator, the
REGEXP operator, or the unicode aware upper()/lower() scalar functions.

FossilOrigin-Name: a079f914522d7bc4b3d27d70114eb09adedfac936a64883e6ed8d382c428dd0e
2017-12-08 16:23:38 +00:00
drh ee15962dd0 Make sure the bComplex variable in sqlite3DeleteFrom() is initialized when
compiling with -DSQLITE_OMIT_TRIGGER.

FossilOrigin-Name: e526d0c40b971d970367a52a57d3920cb64e6a98920114bfac46ba009f0b1eb5
2017-12-08 14:07:14 +00:00
drh b7571b4ecb When doing a table scan using an index, do not error out if collating
functions used by that index are unavailable, since they will not be used.

FossilOrigin-Name: bbd69fa6fa7f3c86fb5cd1b69e1abbe1bbad61aa281e6c073a402d1b202e42ec
2017-12-07 22:10:16 +00:00
mistachkin a0951d875b Fix typo in comment. No changes to code.
FossilOrigin-Name: 95958b60f9282384cac8f29c519d0fa1c32d7c0366c01ce681f6691e5bbf8438
2017-12-07 22:04:53 +00:00
drh 70fedc584d Fix harmless compiler warnings in the rot13 extension.
FossilOrigin-Name: 113470772b04210b9300803124c06af2c0b33278313b311fefe6f80594b24e4a
2017-12-07 16:51:25 +00:00
drh b5008252b3 Updates to the main README.md file.
FossilOrigin-Name: 6bfafc35d1fa0415dcc85edbbd1b273f84b7a6ab75f979b01d90b18ce6aa5703
2017-12-07 13:15:48 +00:00
drh 01f6b2dc2d Fix an unreachable branch in cases when SQLITE_ENABLE_STAT4 is not defined.
FossilOrigin-Name: 6a55bd67720451cdf316155cf348103bfce1056a78bcddf0029b45ff0fdbcc71
2017-12-06 20:50:08 +00:00
dan 8adb25ab63 Fix a compilation problem when both SQLITE_ENABLE_MULTITHREADED_CHECKS and
SQLITE_ENABLE_API_ARMOUR are defined.

FossilOrigin-Name: 0342ce510d2063a63839399a2cfa25b7fc02f4fde17764082676b332d6136241
2017-12-05 14:58:59 +00:00
dan f9679318f2 Fix the ".lint fkey-indexes" shell command so that it works with WITHOUT ROWID
tables.

FossilOrigin-Name: 5771b1d611b3562ea6c040f3f893073c4d0ee58c35b37ae211520d9aee8ed547
2017-12-01 18:40:18 +00:00
dan 92b67025d4 Fix some minor problems in test scripts.
FossilOrigin-Name: 4c551fdebc7feda3dcfeec719387d879cd5e2cbe213c0c1aac0a965b3f9e882d
2017-11-30 11:21:59 +00:00
dan 6302590677 Update test file walprotocol.test to account for the changes in the wal
locking protocol.

FossilOrigin-Name: 64e567009dd56ef595850fe460925bc15fa875163541527638b654aa2b2cf785
2017-11-30 07:55:15 +00:00
dan 3d9c7c3a4f Merge latest trunk changes into this branch.
FossilOrigin-Name: 373fa21bffd37053bb1a741d3ace2f003a5639bf373c20ea7bb24a31080888b3
2017-11-29 16:16:29 +00:00
dan 0895117512 Fix an assertion fault found by OSSFuzz.
FossilOrigin-Name: 75d699877fa7d06d30285ecf008fbedfdf68cc7965bb328c96f5a931d1f13f04
2017-11-28 20:43:40 +00:00
dan 05573e41a8 Lock the wal file for all snapshot transactions, even if they would not
otherwise require this, preventing checkpointers and writers from wrapping the
wal file. This means that if one connection has an open snapshot transaction
it is guaranteed that a second connection can open a transaction on the same
snapshot.

FossilOrigin-Name: b81a31495bd27c1d96f7df653da3502054240cb5acf66b860da7f0f9b422a524
2017-11-28 13:39:41 +00:00
dan 66a1520c73 Add experimental feature to detect threading bugs in apps that use
SQLITE_CONFIG_MULTITHREADED. Enabled at compile time using
SQLITE_ENABLE_MULTITHREADED_CHECKS.

FossilOrigin-Name: 40b598c8392f030f6ed8c63ce81cb0426bb3984397c19c756215f6a569a40164
2017-11-28 07:52:00 +00:00
drh cb45eef4d1 Update tests to deal with SQLITE_FAST_SECURE_DELETE.
FossilOrigin-Name: e6b89304695be371978e65dddd710c8bd563c66b9c94d23165142b6c235c82e1
2017-11-28 00:52:14 +00:00
dan 7ac2d48eba Fix a faulty NEVER assert() that could fail for SQLITE_ENABLE_STAT4 builds
that use foreign keys.

FossilOrigin-Name: 465350e55ddaf30cfba7874653301de7238a9dc2bc5e1f800fc95de9360679f6
2017-11-27 17:56:14 +00:00
drh 9b7affc451 Fix an CSV output quoting problem in the command-line shell on Windows.
FossilOrigin-Name: 6500cdbd36b0169f37fe363c49182b3e30477a51bb521c2a964555cd086a5589
2017-11-26 02:14:18 +00:00
dan 2da1504432 Fix main.mk to name the win32 executable "sqlite3_expert.exe", not
"sqlite3_expert".

FossilOrigin-Name: e38571d518ff399d1033b33843dae60bc61181cdf692dcd8e2e14746bf0d1e61
2017-10-13 16:24:32 +00:00
dan ae542401d8 Update main.mk to build the sqlite3_expert program with -DSQLITE_THREADSAFE=0
and -DSQLITE_OMIT_LOAD_EXTENSION. To minimize dependencies.

FossilOrigin-Name: 4c68ad7da48c941eb1ca0210a85d95467f3f3640bdc55a02686166471806ca4e
2017-10-13 14:20:15 +00:00
drh 85b76a284e Fix the EXPLAIN processing so that it returns SQLITE_ERROR on an OOM, as it
should.

FossilOrigin-Name: 4ec63ef233c9239d3d383a99c234ef6604d55a9838c16f57e56c2a120aeb63c4
2017-10-12 20:24:09 +00:00
dan 4fa5cb3598 Update this branch to match latest trunk.
FossilOrigin-Name: d325da6c50f2f9c10f50b3839f87c155876c339879bb8bdb82567b5ff34ef7ba
2017-10-12 14:13:31 +00:00
dan 518e3f0673 Merge latest trunk changes with this branch.
FossilOrigin-Name: 2719cf5c5bbe8e31d18368d54d968af3878ad2e15f0666e18d7b567d7439c451
2017-10-11 20:26:07 +00:00
dan 7fdb9a7edc Change some internal details to bring this branch closer to the code on trunk.
FossilOrigin-Name: 58e42cfd7d4af2279dab8dd895dca7afbdf9035445bc81bd4a7461ea24e846fc
2017-10-11 20:10:22 +00:00
dan 21f2bafd9b Experimental change so that snapshot transactions always lock the wal file -
preventing writers or truncate-checkpointers from wrapping it.

FossilOrigin-Name: d71eeaab9ecdeed772047498b781be1f0be0655af284b94cf676bb408ceea8b1
2017-09-23 07:46:54 +00:00
drh 31976dacf1 Merge changes from trunk.
FossilOrigin-Name: 6e0f64ab5eafda5d9e61e00c89af3c1ea2c5aa29821da1bdbcab040957b12403
2017-05-15 17:56:48 +00:00
dan e064d572e7 Remove the tool/schemalint.tcl script. And related Makefile entries. It is
superseded by sqlite3_expert.

FossilOrigin-Name: 269bf52e27611cd00fa7f73ee98b395a30dec215232cf1c34f6b741112ba530b
2017-05-04 14:02:05 +00:00
drh bd72749f7d Fix a harmless compiler warning on Windows.
FossilOrigin-Name: 593e5dd00cdf8fbc680951d68b53b38262c61c467703f6a8eb477226cf6beedd
2017-05-03 13:05:08 +00:00
drh bd0f1dbd06 Get sqlite3_expert building on Windows.
FossilOrigin-Name: d8254047b30f7c1be486bf39d4420678604573b951b5cc83c19ebf74aba0864c
2017-05-03 12:50:46 +00:00
drh 138bd6df41 In sqlite3expert.c, do not copy the schema for virtual tables. Updates to
makefiles to make building easier.

FossilOrigin-Name: da15752dccf6090e40ec825db89048eca2b30185882225bf81f1891e914c2e7f
2017-05-03 12:15:20 +00:00
drh 382bce037c In the sqlite3_expert command-line tool, allow two-dash options. Do not
accept the database name if it begins with "-".

FossilOrigin-Name: af7d1596044980e0a18baa3ab6674779724dffbf18a152c72e53f11a08999e68
2017-05-02 20:42:30 +00:00
drh 5034dc673d Merge the latest enhancements from trunk.
FossilOrigin-Name: a7dcf6a79f7e1c5884baee2909a4bf3174ae06d561dae87b390856e573f81b49
2017-05-02 19:45:14 +00:00
dan 6f92c34866 Update this branch with latest trunk changes.
FossilOrigin-Name: 11f4761c3a84e2cc9df62f117a003af8c57f3d226eec5a40d6241b121e78d002
2017-05-01 14:25:34 +00:00
dan f3ac8ba569 Another minor formatting fix.
FossilOrigin-Name: 9fa2ce3c2b75408594d387684984cd946765776d30bc622a1f4e64d6fe1856d5
2017-04-21 19:58:35 +00:00
dan 6b0fa916f5 Fix formatting errors in the previous commit.
FossilOrigin-Name: da9a2e5aa977f7e8e9e4365f7b34bb4f482029a3d44646100773cedc8ea9b959
2017-04-21 19:56:53 +00:00
dan 5b9dbd1ed0 Update the README.md file in the ext/expert/ directory.
FossilOrigin-Name: 3b2ff4e0692dfca395d4523b7d5cd0dfd5c319c1072a2a873631fa477cee0b79
2017-04-21 19:53:39 +00:00
dan c42a0056d7 Merge latest trunk changes into this branch.
FossilOrigin-Name: b1533bc455f52f570c0f4b8aaa0da802757dc89b0e45b9a9b31aa591a44bf7bd
2017-04-20 17:35:46 +00:00
dan ac33c0343f Avoid creating a temp table in the user database in the sqlite3_expert code.
FossilOrigin-Name: 4e366996434e63f06cc451d2011f1f1464360f03430b8260e48f78a612b4e9d6
2017-04-20 17:03:32 +00:00
dan bc3f784cd2 Speed this branch up a bit by filtering before the virtual table layer when
sampling user data.

FossilOrigin-Name: 8e57c31340dd9ffc457da63c5996fb1b573f8154f864ec2b52c15f399906ac8b
2017-04-20 16:43:32 +00:00
dan 6ebd7ff482 Avoid adding INTEGER PRIMARY KEY columns to candidate indexes.
FossilOrigin-Name: 4577fea5cd9d91ea241e9be82797ca1a4447f536e1e4b78a4a569aeb52e78fcb
2017-04-20 16:18:43 +00:00
dan 2ed99def5b Avoid creating a temp table in the user database in the sqlite3_expert code.
Trouble is, this makes sampling for stat1 data much slower.

FossilOrigin-Name: c62e358243d96cb38a7ce2aa679fc640b62bf46080eab4bd5fc2acf5997d6cd5
2017-04-20 16:08:33 +00:00
dan e53b4f9774 Add an option to generate stat1 data based on a subset of the user database
table contents to sqlite3_expert.

FossilOrigin-Name: c69c3e21db6e141f7e24226c6432f2ed31fe5f177bd23781915871f8600ee56a
2017-04-20 09:54:04 +00:00
dan a6ed5a4f39 Have sqlite3_expert_analyze() populate the sqlite_stat1 table before running
queries through the planner for the second time.

FossilOrigin-Name: a157fcfde5afc27ae38e7cf4669fcc8e60e23d9d301ffe2e541dd69f895b493b
2017-04-18 20:10:16 +00:00
dan 7853002c71 Fix sqlite3_expert handling of triggers on views.
FossilOrigin-Name: ff4976da667872614331d88e68fb67d347874f164a1c7950dd738c7c2320b954
2017-04-18 09:04:48 +00:00
dan 280db65e2c Add support for analyzing trigger programs to the sqlite3_expert code.
FossilOrigin-Name: 159e8022a9d6701532b8b60e0c41154bc434c1bbdb107c8c97a78fb1140fa745
2017-04-17 17:03:08 +00:00
dan 2abf90096f Fix problems with handling constraints on the rowid column in sqlite3expert.c.
FossilOrigin-Name: 2e6308798ae2db30564deb35ba3896597448edabbcac6efc4ff084552e42de30
2017-04-15 16:52:12 +00:00
dan 990b6ceccf Merge latest trunk changes into this branch.
FossilOrigin-Name: 2d0c458e013cb2d02fbeabed8dabd66f55141aac194611f0e599b3c95af1964f
2017-04-15 15:47:19 +00:00
dan e01b9281fc Add header comment for sqlite3_vtab_collation().
FossilOrigin-Name: d238694ca445ccb4eeb3e3269a5f872f998f795945d0f9dd95c11d0e42d4d538
2017-04-15 14:30:01 +00:00
dan 79610f5d09 Fix memory leaks in the code on this branch. Make use of the
sqlite3_index_constraint.usage field. Do not try to handle ORDER BY terms with
explicit COLLATE clauses - they don't get passed to the vtab layer anyway.

FossilOrigin-Name: 0cd75a872c89958a7f418720a0e8c6f638f8284c488f666015c19136feae6be8
2017-04-15 14:16:04 +00:00
dan 0824ccf29b Modify the code in ext/expert/ to use the vtab interface instead of
sqlite3_whereinfo_hook(). Remove sqlite3_whereinfo_hook().

FossilOrigin-Name: 3bb6585004090dbf92dd5e9abdf0fd2c921e64b5b3121c4fb7446db764ab59e5
2017-04-14 19:41:37 +00:00
dan 81beb6d115 Update this branch with latest changes from trunk.
FossilOrigin-Name: 5fcd840cf9b6a5c3ee4ef1e8f92f6c30f96a7899a3d774ee9be8a816916f2c3b
2017-04-13 16:19:40 +00:00
dan 0e0f5edbb5 Update this branch with latest trunk changes.
FossilOrigin-Name: 0f66a093935100efd731e14aa63b57360ddd517c1ac97edd1ea9a9de95e1f3cc
2017-04-11 19:00:30 +00:00
dan c2309693b9 Fix a formatting issue in the output of the sqlite3_expert program.
FossilOrigin-Name: cc8c3581060ffef02290b680183e6f6bc9837ba3550e74c8aaabdc7c45edc223
2017-04-11 18:29:14 +00:00
dan a4e61024d7 Add header comments to the API functions in sqlite3expert.h. Include a list of
all candidate indexes in the report output by the sqlite3_expert program.

FossilOrigin-Name: 0c45c5eb9f0f171b8d7c5f0d2973f9f59915467506cdff1450f3e4b2134a01ca
2017-04-11 17:43:12 +00:00
dan 96d43a05ec Add ext/expert/README.md.
FossilOrigin-Name: 9318f1b9ed2d8da3a82ea69179e2d56a99d326c7721642665f87f6a4534e7bf0
2017-04-10 20:00:26 +00:00
dan cd84474ece Changes to allow the code in sqlite3expert.c to be tested directly (via the
API in sqlite3expert.h) instead of by invoking the sqlite3_expert application.
Fix memory leaks and other problems.

FossilOrigin-Name: 5dd9831721b70a89a26728adcd49c7f6103ef8266891a79c2db34d913702709e
2017-04-10 16:13:20 +00:00
dan 958151b005 Fix the -file option on the sqlite3_expert program.
FossilOrigin-Name: 0857c48e02a76490fc623364f77363165dea94ec254f93d8f0fd0bac2968c572
2017-04-09 08:38:37 +00:00
dan 2b78dd2359 Merge latest trunk with this branch.
FossilOrigin-Name: e051e8f21b909c5e89a7203eef6501fecd64f82a634c4e10398b5ef7d716eb37
2017-04-08 19:00:37 +00:00
dan e7c3aca601 Rename shell6.test to expert1.test. Have it invoke the sqlite3_expert binary
if it is present.

FossilOrigin-Name: be0deff940bea4f653d644113f42529a32ff7039d1d168119233aaf000a22f40
2017-04-08 18:56:32 +00:00
dan 65e67ed1b2 Use hash tables instead of in-memory database tables for a few purposes in
sqlite3expert.c.

FossilOrigin-Name: bf10e68d9e4d5eae7ae6148a7ad64c9596f2ed8ccd36065adb09a1f9e7dae50b
2017-04-08 17:41:24 +00:00
dan 8e0b8e0688 Refactor code to suggest indexes from the shell tool into an extension in
ext/expert. Unfinished.

FossilOrigin-Name: 305e19f976ca064638a294e0817bf547ea745e1eb74746c5855514e6ced9c5fa
2017-04-07 20:14:22 +00:00
dan d8ac297233 Changes to allow indexes to be recommended for queries on SQL views.
FossilOrigin-Name: 0884ff1da2e27b146c764b73cf299a1f2cfe213c4a79bde34dec02d1fc946e70
2017-04-06 18:44:18 +00:00
dan 53761f4d52 Add some support for OR terms to sqlite3_whereinfo_hook().
FossilOrigin-Name: 5cd070000da1d9e399090677b4db75dc5639c33211385d6eb84f14a4d0b617cd
2017-04-04 17:50:31 +00:00
dan e86573fa51 Add the sqlite3_whereinfo_hook() API - an experimental API replacing the
DBCONFIG_WHEREINFO hack on this branch.

FossilOrigin-Name: a54aef35da11f7508a8888a159372036a362fc52afa1df752dc835db334c4330
2017-04-04 04:23:06 +00:00
dan fbf3bdcdbc Merge latest trunk into this branch.
FossilOrigin-Name: cb721d0b36268a7b0ef493fa4d7f6bcbaa9ead8b1990e3c3fae015fa1d545226
2017-03-31 11:20:20 +00:00
dan b5c39ac0c9 Update shell6.test to account for the fact that tests are now run in a
separate directory.

FossilOrigin-Name: 1e3622de8b51fdb219eb1934533a95fe6dc5158f44d358bc2efdcb53a4a9fdab
2017-03-31 08:00:03 +00:00
dan ba22f84cc2 Update this branch with latest trunk changes.
FossilOrigin-Name: 249cd361b840913794b7cd2f2d42777dcd547a60
2016-03-15 09:42:39 +00:00
dan 85a18faff9 Merge latest trunk changes with this branch.
FossilOrigin-Name: 59caca4387e97231834a3bffdbed8636be4e8e19
2016-03-09 08:08:51 +00:00
dan 94c67eca89 Fix a problem in the schemalint code that comes up when a sub-query uses one or more of the same tables as its parent.
FossilOrigin-Name: fc18cc9293fb0080b7152c16baac49f44e2db7b3
2016-03-09 08:07:31 +00:00
dan 1447950438 Add test script shell6.test, containing tests for schemalint.
FossilOrigin-Name: 0b73406595c9a077399b0f4c17af3a826cf3612f
2016-02-22 19:51:08 +00:00
dan 850493ac1f Fix a couple of bugs in the schemalint code.
FossilOrigin-Name: 02fbf699c07286f842d9617755f071b0fffc5d40
2016-02-19 07:53:43 +00:00
dan b12dfd0125 Have the schemalint output distinguish between existing and recommended indexes.
FossilOrigin-Name: 4ab3df25f1fee7c8fea19d0c64b3e0e4d3b9c3cf
2016-02-18 19:10:02 +00:00
dan 1c93844dd3 Schemalint changes: Avoid creating candidate indexes if a compatible index exists. Do not quote identifiers that do not require it.
FossilOrigin-Name: cf0f7eeb4f6490b1e3f05b45e83b87cd64640846
2016-02-17 20:06:12 +00:00
dan 94975e27a3 Fix further issues in schemalint.
FossilOrigin-Name: 73a7f010937828c5195a198604f976e8458cef73
2016-02-16 18:37:37 +00:00
dan 47dd4867bc Progress towards integrating schemalint into the shell tool. Some cases work now.
FossilOrigin-Name: 58d4cf26e15f90463148bec63d6ab514ffbbae60
2016-02-15 20:12:16 +00:00
dan 3e6ac1643c Experimental integration of schemalint functionality with the shell tool. Does not work yet.
FossilOrigin-Name: ed49f297bcee86674ed673e195610b8cc1d35647
2016-02-11 21:01:16 +00:00
dan 02e4f27146 Merge latest trunk changes with this branch.
FossilOrigin-Name: 1a4182eedd0143c3f71b3d97f1d1bb25adeba617
2016-02-09 15:10:56 +00:00
dan dbbf8e4eb7 Merge latest trunk changes into this branch.
FossilOrigin-Name: 9341491c3a11d5a66e4f88d2af9b0d3799b4f27a
2016-01-22 14:46:21 +00:00
dan 336bfe06b9 Fix handling of transitive constraints in schemalint.tcl.
FossilOrigin-Name: 44edc1aa3b412ddbe2a242075e2bf36a99437688
2016-01-22 14:44:02 +00:00
dan a494ca8d12 Update the schemalint.tcl script so that the argument to a -select option may be either an SQL statement or the name of a file containing an SQL statement
FossilOrigin-Name: d4e37767671dc946b8a21d0158fc3044e36f0c7e
2016-01-22 14:32:20 +00:00
dan ff3b534b9f Add a rule to main.mk to build the schemalint.tcl script into an executable. Similar to the way the sqlite3_analyzer executable is built.
FossilOrigin-Name: b8251065db9dbe5463490316baa09dc636551377
2015-11-30 19:16:00 +00:00
dan c45bf341af Fix the schemalint.tcl script to handle identifiers that require quoting.
FossilOrigin-Name: 451e0fafbe5b7e9c67d9b584d5e16796c3196881
2015-11-30 18:17:55 +00:00
dan 323f7d3fc6 In the CREATE INDEX statements output by schemalint.tcl, avoid declaring an explicit collation sequence that is the same as the column's default.
FossilOrigin-Name: d3aa067c830e98f2074630c4613c557b0ce90a57
2015-11-23 18:28:07 +00:00
dan 09c480aba1 Merge latest trunk changes with this branch.
FossilOrigin-Name: 8f1ef0904d055b5510ec9043810ebf22a8c5e253
2015-11-23 17:14:03 +00:00
dan 1b8b839a8d Fix ORDER BY handling in the schemalint.tcl script. Add internal self-tests to the same script.
FossilOrigin-Name: b8f277c9b45c4b30e6690e838a30311aa8d84876
2015-11-23 17:10:51 +00:00
dan ef5de04b4e Add support for ORDER BY clauses to schemalint.tcl.
FossilOrigin-Name: 93bdf70e859915ff3696ba0fc68f91ceb2e1a971
2015-11-20 20:55:27 +00:00
dan e7dd68c2d4 Add a hack to debug out a description of the WHERE clause of a SELECT (or other) statement. Use this in script tool/schemalint.tcl to automatically recommend indexes that might speed up specific queries.
FossilOrigin-Name: c6fa01c28ef7ceea2963a92dfffe62eed451b05c
2015-11-11 18:08:58 +00:00
60 changed files with 4414 additions and 491 deletions
+5
View File
@@ -425,6 +425,8 @@ TESTSRC = \
# Statically linked extensions
#
TESTSRC += \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/test_expert.c \
$(TOP)/ext/misc/amatch.c \
$(TOP)/ext/misc/carray.c \
$(TOP)/ext/misc/closure.c \
@@ -1190,6 +1192,9 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
sqlite3_analyzer$(TEXE): sqlite3_analyzer.c
$(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS)
sqlite3_expert$(TEXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
$(LTLINK) $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert $(TLIBS)
CHECKER_DEPS =\
$(TOP)/tool/mkccode.tcl \
sqlite3.c \
+28
View File
@@ -1400,6 +1400,8 @@ TESTSRC = \
# Statically linked extensions.
#
TESTEXT = \
$(TOP)\ext\expert\sqlite3expert.c \
$(TOP)\ext\expert\test_expert.c \
$(TOP)\ext\misc\amatch.c \
$(TOP)\ext\misc\carray.c \
$(TOP)\ext\misc\closure.c \
@@ -2075,6 +2077,24 @@ FTS5_SRC = \
$(TOP)\ext\fts5\fts5_varint.c \
$(TOP)\ext\fts5\fts5_vocab.c
LSM1_SRC = \
$(TOP)\ext\lsm1\lsm.h \
$(TOP)\ext\lsm1\lsmInt.h \
$(TOP)\ext\lsm1\lsm_ckpt.c \
$(TOP)\ext\lsm1\lsm_file.c \
$(TOP)\ext\lsm1\lsm_log.c \
$(TOP)\ext\lsm1\lsm_main.c \
$(TOP)\ext\lsm1\lsm_mem.c \
$(TOP)\ext\lsm1\lsm_mutex.c \
$(TOP)\ext\lsm1\lsm_shared.c \
$(TOP)\ext\lsm1\lsm_sorted.c \
$(TOP)\ext\lsm1\lsm_str.c \
$(TOP)\ext\lsm1\lsm_tree.c \
$(TOP)\ext\lsm1\lsm_unix.c \
$(TOP)\ext\lsm1\lsm_varint.c \
$(TOP)\ext\lsm1\lsm_vtab.c \
$(TOP)\ext\lsm1\lsm_win32.c
fts5parse.c: $(TOP)\ext\fts5\fts5parse.y lemon.exe
copy $(TOP)\ext\fts5\fts5parse.y .
del /Q fts5parse.h 2>NUL
@@ -2086,6 +2106,10 @@ fts5.c: $(FTS5_SRC)
$(TCLSH_CMD) $(TOP)\ext\fts5\tool\mkfts5c.tcl
copy $(TOP)\ext\fts5\fts5.h .
lsm1.c: $(LSM1_SRC)
$(TCLSH_CMD) $(TOP)\ext\lsm1\tool\mklsm1c.tcl
copy $(TOP)\ext\lsm1\lsm.h .
fts5.lo: fts5.c $(HDR) $(EXTHDR)
$(LTCOMPILE) $(CORE_COMPILE_OPTS) $(NO_WARN) -DSQLITE_CORE -c fts5.c
@@ -2198,6 +2222,9 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
$(LTLINK) $(NO_WARN) -DBUILD_sqlite -I$(TCLINCDIR) sqlite3_analyzer.c \
/link $(LDFLAGS) $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
sqlite3_expert.exe: $(SQLITE3C) $(TOP)\ext\expert\sqlite3expert.h $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c
$(LTLINK) $(NO_WARN) $(TOP)\ext\expert\sqlite3expert.c $(TOP)\ext\expert\expert.c $(SQLITE3C) $(TLIBS)
CHECKER_DEPS =\
$(TOP)/tool/mkccode.tcl \
sqlite3.c \
@@ -2315,4 +2342,5 @@ clean:
del /Q sqlite-*-output.vsix 2>NUL
del /Q fuzzershell.exe fuzzcheck.exe sqldiff.exe dbhash.exe 2>NUL
del /Q fts5.* fts5parse.* 2>NUL
del /Q lsm.h lsm1.c 2>NUL
# <</mark>>
+24 -8
View File
@@ -207,8 +207,8 @@ The amalgamation source file is more than 200K lines long. Some symbolic
debuggers (most notably MSVC) are unable to deal with files longer than 64K
lines. To work around this, a separate Tcl script, tool/split-sqlite3c.tcl,
can be run on the amalgamation to break it up into a single small C file
called **sqlite3-all.c** that does #include on about five other files
named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-5.c**. In this way,
called **sqlite3-all.c** that does #include on about seven other files
named **sqlite3-1.c**, **sqlite3-2.c**, ..., **sqlite3-7.c**. In this way,
all of the source code is contained within a single translation unit so
that the compiler can do extra cross-procedure optimization, but no
individual source file exceeds 32K lines in length.
@@ -237,7 +237,8 @@ Key files:
trying to understand how the library works internally.
* **sqliteInt.h** - this header file defines many of the data objects
used internally by SQLite.
used internally by SQLite. In addition to "sqliteInt.h", some
subsystems have their own header files.
* **parse.y** - This file describes the LALR(1) grammar that SQLite uses
to parse SQL statements, and the actions that are taken at each step
@@ -249,29 +250,44 @@ Key files:
which defines internal data objects. The rest of SQLite interacts
with the VDBE through an interface defined by vdbe.h.
* **where.c** - This file analyzes the WHERE clause and generates
* **where.c** - This file (together with its helper files named
by "where*.c") analyzes the WHERE clause and generates
virtual machine code to run queries efficiently. This file is
sometimes called the "query optimizer". It has its own private
header file, whereInt.h, that defines data objects used internally.
* **btree.c** - This file contains the implementation of the B-Tree
storage engine used by SQLite.
storage engine used by SQLite. The interface to the rest of the system
is defined by "btree.h". The "btreeInt.h" header defines objects
used internally by btree.c and not published to the rest of the system.
* **pager.c** - This file contains the "pager" implementation, the
module that implements transactions.
module that implements transactions. The "pager.h" header file
defines the interface between pager.c and the rest of the system.
* **os_unix.c** and **os_win.c** - These two files implement the interface
between SQLite and the underlying operating system using the run-time
pluggable VFS interface.
* **shell.c** - This file is not part of the core SQLite library. This
* **shell.c.in** - This file is not part of the core SQLite library. This
is the file that, when linked against sqlite3.a, generates the
"sqlite3.exe" command-line shell.
"sqlite3.exe" command-line shell. The "shell.c.in" file is transformed
into "shell.c" as part of the build process.
* **tclsqlite.c** - This file implements the Tcl bindings for SQLite. It
is not part of the core SQLite library. But as most of the tests in this
repository are written in Tcl, the Tcl language bindings are important.
* **test*.c** - Files in the src/ folder that begin with "test" go into
building the "testfixture.exe" program. The testfixture.exe program is
an enhanced TCL shell. The testfixture.exe program runs scripts in the
test/ folder to validate the core SQLite code. The testfixture program
(and some other test programs too) is build and run when you type
"make test".
* **ext/misc/json1.c** - This file implements the various JSON functions
that are build into SQLite.
There are many other source files. Each has a succinct header comment that
describes its purpose and role within the larger system.
+83
View File
@@ -0,0 +1,83 @@
## SQLite Expert Extension
This folder contains code for a simple system to propose useful indexes
given a database and a set of SQL queries. It works as follows:
1. The user database schema is copied to a temporary database.
1. All SQL queries are prepared against the temporary database.
Information regarding the WHERE and ORDER BY clauses, and other query
features that affect index selection are recorded.
1. The information gathered in step 2 is used to create candidate
indexes - indexes that the planner might have made use of in the previous
step, had they been available.
1. A subset of the data in the user database is used to generate statistics
for all existing indexes and the candidate indexes generated in step 3
above.
1. The SQL queries are prepared a second time. If the planner uses any
of the indexes created in step 3, they are recommended to the user.
# C API
The SQLite expert C API is defined in sqlite3expert.h. Most uses will proceed
as follows:
1. An sqlite3expert object is created by calling **sqlite3\_expert\_new()**.
A database handle opened by the user is passed as an argument.
1. The sqlite3expert object is configured with one or more SQL statements
by making one or more calls to **sqlite3\_expert\_sql()**. Each call may
specify a single SQL statement, or multiple statements separated by
semi-colons.
1. Optionally, the **sqlite3\_expert\_config()** API may be used to
configure the size of the data subset used to generate index statistics.
Using a smaller subset of the data can speed up the analysis.
1. **sqlite3\_expert\_analyze()** is called to run the analysis.
1. One or more calls are made to **sqlite3\_expert\_report()** to extract
components of the results of the analysis.
1. **sqlite3\_expert\_destroy()** is called to free all resources.
Refer to comments in sqlite3expert.h for further details.
# sqlite3_expert application
The file "expert.c" contains the code for a command line application that
uses the API described above. It can be compiled with (for example):
<pre>
gcc -O2 sqlite3.c expert.c sqlite3expert.c -o sqlite3_expert
</pre>
Assuming the database is named "test.db", it can then be run to analyze a
single query:
<pre>
./sqlite3_expert -sql &lt;sql-query&gt; test.db
</pre>
Or an entire text file worth of queries with:
<pre>
./sqlite3_expert -file &lt;text-file&gt; test.db
</pre>
By default, sqlite3\_expert generates index statistics using all the data in
the user database. For a large database, this may be prohibitively time
consuming. The "-sample" option may be used to configure sqlite3\_expert to
generate statistics based on an integer percentage of the user database as
follows:
<pre>
# Generate statistics based on 25% of the user database rows:
./sqlite3_expert -sample 25 -sql &lt;sql-query&gt; test.db
# Do not generate any statistics at all:
./sqlite3_expert -sample 0 -sql &lt;sql-query&gt; test.db
</pre>
+155
View File
@@ -0,0 +1,155 @@
/*
** 2017 April 07
**
** 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.
**
*************************************************************************
*/
#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqlite3expert.h"
static void option_requires_argument(const char *zOpt){
fprintf(stderr, "Option requires an argument: %s\n", zOpt);
exit(-3);
}
static int option_integer_arg(const char *zVal){
return atoi(zVal);
}
static void usage(char **argv){
fprintf(stderr, "\n");
fprintf(stderr, "Usage %s ?OPTIONS? DATABASE\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "Options are:\n");
fprintf(stderr, " -sql SQL (analyze SQL statements passed as argument)\n");
fprintf(stderr, " -file FILE (read SQL statements from file FILE)\n");
fprintf(stderr, " -verbose LEVEL (integer verbosity level. default 1)\n");
fprintf(stderr, " -sample PERCENT (percent of db to sample. default 100)\n");
exit(-1);
}
static int readSqlFromFile(sqlite3expert *p, const char *zFile, char **pzErr){
FILE *in = fopen(zFile, "rb");
long nIn;
size_t nRead;
char *pBuf;
int rc;
if( in==0 ){
*pzErr = sqlite3_mprintf("failed to open file %s\n", zFile);
return SQLITE_ERROR;
}
fseek(in, 0, SEEK_END);
nIn = ftell(in);
rewind(in);
pBuf = sqlite3_malloc64( nIn+1 );
nRead = fread(pBuf, nIn, 1, in);
fclose(in);
if( nRead!=1 ){
sqlite3_free(pBuf);
*pzErr = sqlite3_mprintf("failed to read file %s\n", zFile);
return SQLITE_ERROR;
}
pBuf[nIn] = 0;
rc = sqlite3_expert_sql(p, pBuf, pzErr);
sqlite3_free(pBuf);
return rc;
}
int main(int argc, char **argv){
const char *zDb;
int rc = 0;
char *zErr = 0;
int i;
int iVerbose = 1; /* -verbose option */
sqlite3 *db = 0;
sqlite3expert *p = 0;
if( argc<2 ) usage(argv);
zDb = argv[argc-1];
if( zDb[0]=='-' ) usage(argv);
rc = sqlite3_open(zDb, &db);
if( rc!=SQLITE_OK ){
fprintf(stderr, "Cannot open db file: %s - %s\n", zDb, sqlite3_errmsg(db));
exit(-2);
}
p = sqlite3_expert_new(db, &zErr);
if( p==0 ){
fprintf(stderr, "Cannot run analysis: %s\n", zErr);
rc = 1;
}else{
for(i=1; i<(argc-1); i++){
char *zArg = argv[i];
if( zArg[0]=='-' && zArg[1]=='-' && zArg[2]!=0 ) zArg++;
int nArg = (int)strlen(zArg);
if( nArg>=2 && 0==sqlite3_strnicmp(zArg, "-file", nArg) ){
if( ++i==(argc-1) ) option_requires_argument("-file");
rc = readSqlFromFile(p, argv[i], &zErr);
}
else if( nArg>=3 && 0==sqlite3_strnicmp(zArg, "-sql", nArg) ){
if( ++i==(argc-1) ) option_requires_argument("-sql");
rc = sqlite3_expert_sql(p, argv[i], &zErr);
}
else if( nArg>=3 && 0==sqlite3_strnicmp(zArg, "-sample", nArg) ){
int iSample;
if( ++i==(argc-1) ) option_requires_argument("-sample");
iSample = option_integer_arg(argv[i]);
sqlite3_expert_config(p, EXPERT_CONFIG_SAMPLE, iSample);
}
else if( nArg>=2 && 0==sqlite3_strnicmp(zArg, "-verbose", nArg) ){
if( ++i==(argc-1) ) option_requires_argument("-verbose");
iVerbose = option_integer_arg(argv[i]);
}
else{
usage(argv);
}
}
}
if( rc==SQLITE_OK ){
rc = sqlite3_expert_analyze(p, &zErr);
}
if( rc==SQLITE_OK ){
int nQuery = sqlite3_expert_count(p);
if( iVerbose>0 ){
const char *zCand = sqlite3_expert_report(p,0,EXPERT_REPORT_CANDIDATES);
fprintf(stdout, "-- Candidates -------------------------------\n");
fprintf(stdout, "%s\n", zCand);
}
for(i=0; i<nQuery; i++){
const char *zSql = sqlite3_expert_report(p, i, EXPERT_REPORT_SQL);
const char *zIdx = sqlite3_expert_report(p, i, EXPERT_REPORT_INDEXES);
const char *zEQP = sqlite3_expert_report(p, i, EXPERT_REPORT_PLAN);
if( zIdx==0 ) zIdx = "(no new indexes)\n";
if( iVerbose>0 ){
fprintf(stdout, "-- Query %d ----------------------------------\n",i+1);
fprintf(stdout, "%s\n\n", zSql);
}
fprintf(stdout, "%s\n%s\n", zIdx, zEQP);
}
}else{
fprintf(stderr, "Error: %s\n", zErr ? zErr : "?");
}
sqlite3_expert_destroy(p);
sqlite3_free(zErr);
return rc;
}
+360
View File
@@ -0,0 +1,360 @@
# 2009 Nov 11
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
# The focus of this file is testing the CLI shell tool. Specifically,
# the ".recommend" command.
#
#
# Test plan:
#
#
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
set testprefix expert1
if {$tcl_platform(platform)=="windows"} {
set CMD "sqlite3_expert.exe"
} else {
set CMD ".././sqlite3_expert"
}
proc squish {txt} {
regsub -all {[[:space:]]+} $txt { }
}
proc do_setup_rec_test {tn setup sql res} {
reset_db
db eval $setup
uplevel [list do_rec_test $tn $sql $res]
}
foreach {tn setup} {
1 {
if {![file executable $CMD]} { continue }
proc do_rec_test {tn sql res} {
set res [squish [string trim $res]]
set tst [subst -nocommands {
squish [string trim [exec $::CMD -verbose 0 -sql {$sql;} test.db]]
}]
uplevel [list do_test $tn $tst $res]
}
}
2 {
if {[info commands sqlite3_expert_new]==""} { continue }
proc do_rec_test {tn sql res} {
set expert [sqlite3_expert_new db]
$expert sql $sql
$expert analyze
set result [list]
for {set i 0} {$i < [$expert count]} {incr i} {
set idx [string trim [$expert report $i indexes]]
if {$idx==""} {set idx "(no new indexes)"}
lappend result $idx
lappend result [string trim [$expert report $i plan]]
}
$expert destroy
set tst [subst -nocommands {set {} [squish [join {$result}]]}]
uplevel [list do_test $tn $tst [string trim [squish $res]]]
}
}
} {
eval $setup
do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } {
SELECT * FROM t1
} {
(no new indexes)
0|0|0|SCAN TABLE t1
}
do_setup_rec_test $tn.2 {
CREATE TABLE t1(a, b, c);
} {
SELECT * FROM t1 WHERE b>?;
} {
CREATE INDEX t1_idx_00000062 ON t1(b);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000062 (b>?)
}
do_setup_rec_test $tn.3 {
CREATE TABLE t1(a, b, c);
} {
SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ?
} {
CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_3e094c27 (b>? AND b<?)
}
do_setup_rec_test $tn.4 {
CREATE TABLE t1(a, b, c);
} {
SELECT a FROM t1 ORDER BY b;
} {
CREATE INDEX t1_idx_00000062 ON t1(b);
0|0|0|SCAN TABLE t1 USING INDEX t1_idx_00000062
}
do_setup_rec_test $tn.5 {
CREATE TABLE t1(a, b, c);
} {
SELECT a FROM t1 WHERE a=? ORDER BY b;
} {
CREATE INDEX t1_idx_000123a7 ON t1(a, b);
0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?)
}
do_setup_rec_test $tn.6 {
CREATE TABLE t1(a, b, c);
} {
SELECT min(a) FROM t1
} {
CREATE INDEX t1_idx_00000061 ON t1(a);
0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061
}
do_setup_rec_test $tn.7 {
CREATE TABLE t1(a, b, c);
} {
SELECT * FROM t1 ORDER BY a, b, c;
} {
CREATE INDEX t1_idx_033e95fe ON t1(a, b, c);
0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_033e95fe
}
#do_setup_rec_test $tn.1.8 {
# CREATE TABLE t1(a, b, c);
#} {
# SELECT * FROM t1 ORDER BY a ASC, b COLLATE nocase DESC, c ASC;
#} {
# CREATE INDEX t1_idx_5be6e222 ON t1(a, b COLLATE NOCASE DESC, c);
# 0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_5be6e222
#}
do_setup_rec_test $tn.8.1 {
CREATE TABLE t1(a COLLATE NOCase, b, c);
} {
SELECT * FROM t1 WHERE a=?
} {
CREATE INDEX t1_idx_00000061 ON t1(a);
0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000061 (a=?)
}
do_setup_rec_test $tn.8.2 {
CREATE TABLE t1(a, b COLLATE nocase, c);
} {
SELECT * FROM t1 ORDER BY a ASC, b DESC, c ASC;
} {
CREATE INDEX t1_idx_5cb97285 ON t1(a, b DESC, c);
0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_5cb97285
}
# Tables with names that require quotes.
#
do_setup_rec_test $tn.9.1 {
CREATE TABLE "t t"(a, b, c);
} {
SELECT * FROM "t t" WHERE a=?
} {
CREATE INDEX 't t_idx_00000061' ON 't t'(a);
0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000061 (a=?)
}
do_setup_rec_test $tn.9.2 {
CREATE TABLE "t t"(a, b, c);
} {
SELECT * FROM "t t" WHERE b BETWEEN ? AND ?
} {
CREATE INDEX 't t_idx_00000062' ON 't t'(b);
0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000062 (b>? AND b<?)
}
# Columns with names that require quotes.
#
do_setup_rec_test $tn.10.1 {
CREATE TABLE t3(a, "b b", c);
} {
SELECT * FROM t3 WHERE "b b" = ?
} {
CREATE INDEX t3_idx_00050c52 ON t3('b b');
0|0|0|SEARCH TABLE t3 USING INDEX t3_idx_00050c52 (b b=?)
}
do_setup_rec_test $tn.10.2 {
CREATE TABLE t3(a, "b b", c);
} {
SELECT * FROM t3 ORDER BY "b b"
} {
CREATE INDEX t3_idx_00050c52 ON t3('b b');
0|0|0|SCAN TABLE t3 USING INDEX t3_idx_00050c52
}
# Transitive constraints
#
do_setup_rec_test $tn.11.1 {
CREATE TABLE t5(a, b);
CREATE TABLE t6(c, d);
} {
SELECT * FROM t5, t6 WHERE a=? AND b=c AND c=?
} {
CREATE INDEX t5_idx_000123a7 ON t5(a, b);
CREATE INDEX t6_idx_00000063 ON t6(c);
0|0|1|SEARCH TABLE t6 USING INDEX t6_idx_00000063 (c=?)
0|1|0|SEARCH TABLE t5 USING COVERING INDEX t5_idx_000123a7 (a=? AND b=?)
}
# OR terms.
#
do_setup_rec_test $tn.12.1 {
CREATE TABLE t7(a, b);
} {
SELECT * FROM t7 WHERE a=? OR b=?
} {
CREATE INDEX t7_idx_00000062 ON t7(b);
CREATE INDEX t7_idx_00000061 ON t7(a);
0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?)
0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?)
}
# rowid terms.
#
do_setup_rec_test $tn.13.1 {
CREATE TABLE t8(a, b);
} {
SELECT * FROM t8 WHERE rowid=?
} {
(no new indexes)
0|0|0|SEARCH TABLE t8 USING INTEGER PRIMARY KEY (rowid=?)
}
do_setup_rec_test $tn.13.2 {
CREATE TABLE t8(a, b);
} {
SELECT * FROM t8 ORDER BY rowid
} {
(no new indexes)
0|0|0|SCAN TABLE t8
}
do_setup_rec_test $tn.13.3 {
CREATE TABLE t8(a, b);
} {
SELECT * FROM t8 WHERE a=? ORDER BY rowid
} {
CREATE INDEX t8_idx_00000061 ON t8(a);
0|0|0|SEARCH TABLE t8 USING INDEX t8_idx_00000061 (a=?)
}
# Triggers
#
do_setup_rec_test $tn.14 {
CREATE TABLE t9(a, b, c);
CREATE TABLE t10(a, b, c);
CREATE TRIGGER t9t AFTER INSERT ON t9 BEGIN
UPDATE t10 SET a=new.a WHERE b = new.b;
END;
} {
INSERT INTO t9 VALUES(?, ?, ?);
} {
CREATE INDEX t10_idx_00000062 ON t10(b);
0|0|0|SEARCH TABLE t10 USING INDEX t10_idx_00000062 (b=?)
}
do_setup_rec_test $tn.15 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t1 SELECT (i-1)/50, (i-1)/20 FROM s;
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
} {
SELECT * FROM t2, t1 WHERE b=? AND d=? AND t2.rowid=t1.rowid
} {
CREATE INDEX t2_idx_00000064 ON t2(d);
0|0|0|SEARCH TABLE t2 USING INDEX t2_idx_00000064 (d=?)
0|1|1|SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)
}
}
proc do_candidates_test {tn sql res} {
set res [squish [string trim $res]]
set expert [sqlite3_expert_new db]
$expert sql $sql
$expert analyze
set candidates [squish [string trim [$expert report 0 candidates]]]
$expert destroy
uplevel [list do_test $tn [list set {} $candidates] $res]
}
reset_db
do_execsql_test 3.0 {
CREATE TABLE t1(a, b);
CREATE TABLE t2(c, d);
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t1 SELECT (i-1)/50, (i-1)/20 FROM s;
WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100)
INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s;
}
do_candidates_test 3.1 {
SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?)
} {
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50
CREATE INDEX t2_idx_00000063 ON t2(c); -- stat1: 100 20
CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5
}
do_candidates_test 3.2 {
SELECT * FROM t1,t2 WHERE a=? AND b=? AND c=? AND d=?
} {
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 17
CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5
}
do_execsql_test 3.2 {
CREATE INDEX t1_idx_00000061 ON t1(a); -- stat1: 100 50
CREATE INDEX t1_idx_00000062 ON t1(b); -- stat1: 100 20
CREATE INDEX t1_idx_000123a7 ON t1(a, b); -- stat1: 100 50 16
CREATE INDEX t2_idx_00000063 ON t2(c); -- stat1: 100 20
CREATE INDEX t2_idx_00000064 ON t2(d); -- stat1: 100 5
CREATE INDEX t2_idx_0001295b ON t2(c, d); -- stat1: 100 20 5
ANALYZE;
SELECT * FROM sqlite_stat1 ORDER BY 1, 2;
} {
t1 t1_idx_00000061 {100 50}
t1 t1_idx_00000062 {100 20}
t1 t1_idx_000123a7 {100 50 17}
t2 t2_idx_00000063 {100 20}
t2 t2_idx_00000064 {100 5}
t2 t2_idx_0001295b {100 20 5}
}
finish_test
File diff suppressed because it is too large Load Diff
+168
View File
@@ -0,0 +1,168 @@
/*
** 2017 April 07
**
** 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.
**
*************************************************************************
*/
#include "sqlite3.h"
typedef struct sqlite3expert sqlite3expert;
/*
** Create a new sqlite3expert object.
**
** If successful, a pointer to the new object is returned and (*pzErr) set
** to NULL. Or, if an error occurs, NULL is returned and (*pzErr) set to
** an English-language error message. In this case it is the responsibility
** of the caller to eventually free the error message buffer using
** sqlite3_free().
*/
sqlite3expert *sqlite3_expert_new(sqlite3 *db, char **pzErr);
/*
** Configure an sqlite3expert object.
**
** EXPERT_CONFIG_SAMPLE:
** By default, sqlite3_expert_analyze() generates sqlite_stat1 data for
** each candidate index. This involves scanning and sorting the entire
** contents of each user database table once for each candidate index
** associated with the table. For large databases, this can be
** prohibitively slow. This option allows the sqlite3expert object to
** be configured so that sqlite_stat1 data is instead generated based on a
** subset of each table, or so that no sqlite_stat1 data is used at all.
**
** A single integer argument is passed to this option. If the value is less
** than or equal to zero, then no sqlite_stat1 data is generated or used by
** the analysis - indexes are recommended based on the database schema only.
** Or, if the value is 100 or greater, complete sqlite_stat1 data is
** generated for each candidate index (this is the default). Finally, if the
** value falls between 0 and 100, then it represents the percentage of user
** table rows that should be considered when generating sqlite_stat1 data.
**
** Examples:
**
** // Do not generate any sqlite_stat1 data
** sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 0);
**
** // Generate sqlite_stat1 data based on 10% of the rows in each table.
** sqlite3_expert_config(pExpert, EXPERT_CONFIG_SAMPLE, 10);
*/
int sqlite3_expert_config(sqlite3expert *p, int op, ...);
#define EXPERT_CONFIG_SAMPLE 1 /* int */
/*
** Specify zero or more SQL statements to be included in the analysis.
**
** Buffer zSql must contain zero or more complete SQL statements. This
** function parses all statements contained in the buffer and adds them
** to the internal list of statements to analyze. If successful, SQLITE_OK
** is returned and (*pzErr) set to NULL. Or, if an error occurs - for example
** due to a error in the SQL - an SQLite error code is returned and (*pzErr)
** may be set to point to an English language error message. In this case
** the caller is responsible for eventually freeing the error message buffer
** using sqlite3_free().
**
** If an error does occur while processing one of the statements in the
** buffer passed as the second argument, none of the statements in the
** buffer are added to the analysis.
**
** This function must be called before sqlite3_expert_analyze(). If a call
** to this function is made on an sqlite3expert object that has already
** been passed to sqlite3_expert_analyze() SQLITE_MISUSE is returned
** immediately and no statements are added to the analysis.
*/
int sqlite3_expert_sql(
sqlite3expert *p, /* From a successful sqlite3_expert_new() */
const char *zSql, /* SQL statement(s) to add */
char **pzErr /* OUT: Error message (if any) */
);
/*
** This function is called after the sqlite3expert object has been configured
** with all SQL statements using sqlite3_expert_sql() to actually perform
** the analysis. Once this function has been called, it is not possible to
** add further SQL statements to the analysis.
**
** If successful, SQLITE_OK is returned and (*pzErr) is set to NULL. Or, if
** an error occurs, an SQLite error code is returned and (*pzErr) set to
** point to a buffer containing an English language error message. In this
** case it is the responsibility of the caller to eventually free the buffer
** using sqlite3_free().
**
** If an error does occur within this function, the sqlite3expert object
** is no longer useful for any purpose. At that point it is no longer
** possible to add further SQL statements to the object or to re-attempt
** the analysis. The sqlite3expert object must still be freed using a call
** sqlite3_expert_destroy().
*/
int sqlite3_expert_analyze(sqlite3expert *p, char **pzErr);
/*
** Return the total number of statements loaded using sqlite3_expert_sql().
** The total number of SQL statements may be different from the total number
** to calls to sqlite3_expert_sql().
*/
int sqlite3_expert_count(sqlite3expert*);
/*
** Return a component of the report.
**
** This function is called after sqlite3_expert_analyze() to extract the
** results of the analysis. Each call to this function returns either a
** NULL pointer or a pointer to a buffer containing a nul-terminated string.
** The value passed as the third argument must be one of the EXPERT_REPORT_*
** #define constants defined below.
**
** For some EXPERT_REPORT_* parameters, the buffer returned contains
** information relating to a specific SQL statement. In these cases that
** SQL statement is identified by the value passed as the second argument.
** SQL statements are numbered from 0 in the order in which they are parsed.
** If an out-of-range value (less than zero or equal to or greater than the
** value returned by sqlite3_expert_count()) is passed as the second argument
** along with such an EXPERT_REPORT_* parameter, NULL is always returned.
**
** EXPERT_REPORT_SQL:
** Return the text of SQL statement iStmt.
**
** EXPERT_REPORT_INDEXES:
** Return a buffer containing the CREATE INDEX statements for all recommended
** indexes for statement iStmt. If there are no new recommeded indexes, NULL
** is returned.
**
** EXPERT_REPORT_PLAN:
** Return a buffer containing the EXPLAIN QUERY PLAN output for SQL query
** iStmt after the proposed indexes have been added to the database schema.
**
** EXPERT_REPORT_CANDIDATES:
** Return a pointer to a buffer containing the CREATE INDEX statements
** for all indexes that were tested (for all SQL statements). The iStmt
** parameter is ignored for EXPERT_REPORT_CANDIDATES calls.
*/
const char *sqlite3_expert_report(sqlite3expert*, int iStmt, int eReport);
/*
** Values for the third argument passed to sqlite3_expert_report().
*/
#define EXPERT_REPORT_SQL 1
#define EXPERT_REPORT_INDEXES 2
#define EXPERT_REPORT_PLAN 3
#define EXPERT_REPORT_CANDIDATES 4
/*
** Free an (sqlite3expert*) handle and all associated resources. There
** should be one call to this function for each successful call to
** sqlite3-expert_new().
*/
void sqlite3_expert_destroy(sqlite3expert*);
+215
View File
@@ -0,0 +1,215 @@
/*
** 2017 April 07
**
** 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.
**
*************************************************************************
*/
#if defined(SQLITE_TEST)
#include "sqlite3expert.h"
#include <assert.h>
#include <string.h>
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
/*
** Extract an sqlite3* db handle from the object passed as the second
** argument. If successful, set *pDb to point to the db handle and return
** TCL_OK. Otherwise, return TCL_ERROR.
*/
static int dbHandleFromObj(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **pDb){
Tcl_CmdInfo info;
if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(pObj), &info) ){
Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(pObj), 0);
return TCL_ERROR;
}
*pDb = *(sqlite3 **)info.objClientData;
return TCL_OK;
}
/*
** Tclcmd: $expert sql SQL
** $expert analyze
** $expert count
** $expert report STMT EREPORT
** $expert destroy
*/
static int SQLITE_TCLAPI testExpertCmd(
void *clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
sqlite3expert *pExpert = (sqlite3expert*)clientData;
struct Subcmd {
const char *zSub;
int nArg;
const char *zMsg;
} aSub[] = {
{ "sql", 1, "TABLE", }, /* 0 */
{ "analyze", 0, "", }, /* 1 */
{ "count", 0, "", }, /* 2 */
{ "report", 2, "STMT EREPORT", }, /* 3 */
{ "destroy", 0, "", }, /* 4 */
{ 0 }
};
int iSub;
int rc = TCL_OK;
char *zErr = 0;
if( objc<2 ){
Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
return TCL_ERROR;
}
rc = Tcl_GetIndexFromObjStruct(interp,
objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub
);
if( rc!=TCL_OK ) return rc;
if( objc!=2+aSub[iSub].nArg ){
Tcl_WrongNumArgs(interp, 2, objv, aSub[iSub].zMsg);
return TCL_ERROR;
}
switch( iSub ){
case 0: { /* sql */
char *zArg = Tcl_GetString(objv[2]);
rc = sqlite3_expert_sql(pExpert, zArg, &zErr);
break;
}
case 1: { /* analyze */
rc = sqlite3_expert_analyze(pExpert, &zErr);
break;
}
case 2: { /* count */
int n = sqlite3_expert_count(pExpert);
Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
break;
}
case 3: { /* report */
const char *aEnum[] = {
"sql", "indexes", "plan", "candidates", 0
};
int iEnum;
int iStmt;
const char *zReport;
if( Tcl_GetIntFromObj(interp, objv[2], &iStmt)
|| Tcl_GetIndexFromObj(interp, objv[3], aEnum, "report", 0, &iEnum)
){
return TCL_ERROR;
}
assert( EXPERT_REPORT_SQL==1 );
assert( EXPERT_REPORT_INDEXES==2 );
assert( EXPERT_REPORT_PLAN==3 );
assert( EXPERT_REPORT_CANDIDATES==4 );
zReport = sqlite3_expert_report(pExpert, iStmt, 1+iEnum);
Tcl_SetObjResult(interp, Tcl_NewStringObj(zReport, -1));
break;
}
default: /* destroy */
assert( iSub==4 );
Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
break;
}
if( rc!=TCL_OK ){
if( zErr ){
Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
}else{
extern const char *sqlite3ErrName(int);
Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
}
}
sqlite3_free(zErr);
return rc;
}
static void SQLITE_TCLAPI testExpertDel(void *clientData){
sqlite3expert *pExpert = (sqlite3expert*)clientData;
sqlite3_expert_destroy(pExpert);
}
/*
** sqlite3_expert_new DB
*/
static int SQLITE_TCLAPI test_sqlite3_expert_new(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
static int iCmd = 0;
sqlite3 *db;
char *zCmd = 0;
char *zErr = 0;
sqlite3expert *pExpert;
int rc = TCL_OK;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB");
return TCL_ERROR;
}
if( dbHandleFromObj(interp, objv[1], &db) ){
return TCL_ERROR;
}
zCmd = sqlite3_mprintf("sqlite3expert%d", ++iCmd);
if( zCmd==0 ){
Tcl_AppendResult(interp, "out of memory", (char*)0);
return TCL_ERROR;
}
pExpert = sqlite3_expert_new(db, &zErr);
if( pExpert==0 ){
Tcl_AppendResult(interp, zErr, (char*)0);
rc = TCL_ERROR;
}else{
void *p = (void*)pExpert;
Tcl_CreateObjCommand(interp, zCmd, testExpertCmd, p, testExpertDel);
Tcl_SetObjResult(interp, Tcl_NewStringObj(zCmd, -1));
}
sqlite3_free(zCmd);
sqlite3_free(zErr);
return rc;
}
int TestExpert_Init(Tcl_Interp *interp){
struct Cmd {
const char *zCmd;
Tcl_ObjCmdProc *xProc;
} aCmd[] = {
{ "sqlite3_expert_new", test_sqlite3_expert_new },
};
int i;
for(i=0; i<sizeof(aCmd)/sizeof(struct Cmd); i++){
struct Cmd *p = &aCmd[i];
Tcl_CreateObjCommand(interp, p->zCmd, p->xProc, 0, 0);
}
return TCL_OK;
}
#endif
+8 -1
View File
@@ -4909,7 +4909,13 @@ static void fts5MergePrefixLists(
Fts5Buffer out = {0, 0, 0};
Fts5Buffer tmp = {0, 0, 0};
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n) ) return;
/* The maximum size of the output is equal to the sum of the two
** input sizes + 1 varint (9 bytes). The extra varint is because if the
** first rowid in one input is a large negative number, and the first in
** the other a non-negative number, the delta for the non-negative
** number will be larger on disk than the literal integer value
** was. */
if( sqlite3Fts5BufferSize(&p->rc, &out, p1->n + p2->n + 9) ) return;
fts5DoclistIterInit(p1, &i1);
fts5DoclistIterInit(p2, &i2);
@@ -5003,6 +5009,7 @@ static void fts5MergePrefixLists(
fts5MergeAppendDocid(&out, iLastRowid, i2.iRowid);
fts5BufferSafeAppendBlob(&out, i2.aPoslist, i2.aEof - i2.aPoslist);
}
assert( out.n<=(p1->n+p2->n+9) );
fts5BufferSet(&p->rc, p1, out.n, out.p);
fts5BufferFree(&tmp);
+11 -1
View File
@@ -64,7 +64,7 @@ for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} {
execsql COMMIT
} {}
do_execsql_test 1.$tn.2 {
do_execsql_test 2.$tn.2 {
INSERT INTO t1(t1) VALUES('integrity-check');
}
@@ -77,5 +77,15 @@ for {set tn 1 ; set pgsz 64} {$tn<32} {incr tn; incr pgsz 16} {
}
}
reset_db
do_execsql_test 3.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a);
INSERT INTO x1(rowid, a) VALUES(-1000000000000, 'toyota');
INSERT INTO x1(rowid, a) VALUES(1, 'tarago');
}
do_execsql_test 3.1 {
SELECT rowid FROM x1('t*');
} {-1000000000000 1}
finish_test
+27 -20
View File
@@ -28,7 +28,9 @@
** provide case-independent matching.
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
#if !defined(SQLITE_CORE) \
|| defined(SQLITE_ENABLE_ICU) \
|| defined(SQLITE_ENABLE_ICU_COLLATIONS)
/* Include ICU headers */
#include <unicode/utypes.h>
@@ -45,6 +47,26 @@
#include "sqlite3.h"
#endif
/*
** This function is called when an ICU function called from within
** the implementation of an SQL scalar function returns an error.
**
** The scalar function context passed as the first argument is
** loaded with an error message based on the following two args.
*/
static void icuFunctionError(
sqlite3_context *pCtx, /* SQLite scalar function context */
const char *zName, /* Name of ICU function that failed */
UErrorCode e /* Error code returned by ICU function */
){
char zBuf[128];
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
zBuf[127] = '\0';
sqlite3_result_error(pCtx, zBuf, -1);
}
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
/*
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
** operator.
@@ -224,24 +246,6 @@ static void icuLikeFunc(
}
}
/*
** This function is called when an ICU function called from within
** the implementation of an SQL scalar function returns an error.
**
** The scalar function context passed as the first argument is
** loaded with an error message based on the following two args.
*/
static void icuFunctionError(
sqlite3_context *pCtx, /* SQLite scalar function context */
const char *zName, /* Name of ICU function that failed */
UErrorCode e /* Error code returned by ICU function */
){
char zBuf[128];
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
zBuf[127] = '\0';
sqlite3_result_error(pCtx, zBuf, -1);
}
/*
** Function to delete compiled regexp objects. Registered as
** a destructor function with sqlite3_set_auxdata().
@@ -407,6 +411,8 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
assert( 0 ); /* Unreachable */
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
/*
** Collation sequence destructor function. The pCtx argument points to
** a UCollator structure previously allocated using ucol_open().
@@ -501,6 +507,7 @@ int sqlite3IcuInit(sqlite3 *db){
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} scalars[] = {
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
@@ -512,10 +519,10 @@ int sqlite3IcuInit(sqlite3 *db){
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
};
int rc = SQLITE_OK;
int i;
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
const struct IcuScalar *p = &scalars[i];
+18 -18
View File
@@ -110,7 +110,7 @@ typedef unsigned long long int u64;
#endif
/* A page number is a 64-bit integer. */
typedef i64 Pgno;
typedef i64 LsmPgno;
#ifdef LSM_DEBUG
int lsmErrorBkpt(int);
@@ -402,9 +402,9 @@ struct lsm_db {
};
struct Segment {
Pgno iFirst; /* First page of this run */
Pgno iLastPg; /* Last page of this run */
Pgno iRoot; /* Root page number (if any) */
LsmPgno iFirst; /* First page of this run */
LsmPgno iLastPg; /* Last page of this run */
LsmPgno iRoot; /* Root page number (if any) */
int nSize; /* Size of this run in pages */
Redirect *pRedirect; /* Block redirects (or NULL) */
@@ -456,7 +456,7 @@ struct Level {
** output segment.
*/
struct MergeInput {
Pgno iPg; /* Page on which next input is stored */
LsmPgno iPg; /* Page on which next input is stored */
int iCell; /* Cell containing next input to merge */
};
struct Merge {
@@ -465,7 +465,7 @@ struct Merge {
MergeInput splitkey; /* Location in file of current splitkey */
int nSkip; /* Number of separators entries to skip */
int iOutputOff; /* Write offset on output page */
Pgno iCurrentPtr; /* Current pointer value */
LsmPgno iCurrentPtr; /* Current pointer value */
};
/*
@@ -579,10 +579,10 @@ struct Snapshot {
Redirect redirect; /* Block redirection array */
/* Used by worker snapshots only */
int nBlock; /* Number of blocks in database file */
Pgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
Freelist freelist; /* Free block list */
u32 nWrite; /* Total number of pages written to disk */
int nBlock; /* Number of blocks in database file */
LsmPgno aiAppend[LSM_APPLIST_SZ]; /* Append point list */
Freelist freelist; /* Free block list */
u32 nWrite; /* Total number of pages written to disk */
};
#define LSM_INITIAL_SNAPSHOT_ID 11
@@ -710,7 +710,7 @@ void lsmFsSetPageSize(FileSystem *, int);
int lsmFsFileid(lsm_db *pDb, void **ppId, int *pnId);
/* Creating, populating, gobbling and deleting sorted runs. */
void lsmFsGobble(lsm_db *, Segment *, Pgno *, int);
void lsmFsGobble(lsm_db *, Segment *, LsmPgno *, int);
int lsmFsSortedDelete(FileSystem *, Snapshot *, int, Segment *);
int lsmFsSortedFinish(FileSystem *, Segment *);
int lsmFsSortedAppend(FileSystem *, Snapshot *, Level *, int, Page **);
@@ -727,14 +727,14 @@ void lsmSortedSplitkey(lsm_db *, Level *, int *);
/* Reading sorted run content. */
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg);
int lsmFsDbPageGet(FileSystem *, Segment *, Pgno, Page **);
int lsmFsDbPageGet(FileSystem *, Segment *, LsmPgno, Page **);
int lsmFsDbPageNext(Segment *, Page *, int eDir, Page **);
u8 *lsmFsPageData(Page *, int *);
int lsmFsPageRelease(Page *);
int lsmFsPagePersist(Page *);
void lsmFsPageRef(Page *);
Pgno lsmFsPageNumber(Page *);
LsmPgno lsmFsPageNumber(Page *);
int lsmFsNRead(FileSystem *);
int lsmFsNWrite(FileSystem *);
@@ -748,7 +748,7 @@ int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg);
int lsmFsIntegrityCheck(lsm_db *);
#endif
Pgno lsmFsRedirectPage(FileSystem *, Redirect *, Pgno);
LsmPgno lsmFsRedirectPage(FileSystem *, Redirect *, LsmPgno);
int lsmFsPageWritable(Page *);
@@ -768,8 +768,8 @@ int lsmFsSyncDb(FileSystem *, int);
void lsmFsFlushWaiting(FileSystem *, int *);
/* Used by lsm_info(ARRAY_STRUCTURE) and lsm_config(MMAP) */
int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, Pgno iFirst, char **pzOut);
int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut);
int lsmInfoArrayStructure(lsm_db *pDb, int bBlock, LsmPgno iFirst, char **pz);
int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut);
int lsmConfigMmap(lsm_db *pDb, int *piParam);
int lsmEnvOpen(lsm_env *, const char *, int, lsm_file **);
@@ -785,7 +785,7 @@ void lsmEnvSleep(lsm_env *, int);
int lsmFsReadSyncedId(lsm_db *db, int, i64 *piVal);
int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, Pgno, int *);
int lsmFsSegmentContainsPg(FileSystem *pFS, Segment *, LsmPgno, int *);
void lsmFsPurgeCache(FileSystem *);
@@ -796,7 +796,7 @@ void lsmFsPurgeCache(FileSystem *);
/*
** Functions from file "lsm_sorted.c".
*/
int lsmInfoPageDump(lsm_db *, Pgno, int, char **);
int lsmInfoPageDump(lsm_db *, LsmPgno, int, char **);
void lsmSortedCleanup(lsm_db *);
int lsmSortedAutoWork(lsm_db *, int nUnit);
+1 -1
View File
@@ -389,7 +389,7 @@ static void ckptExportAppendlist(
int *pRc /* IN/OUT: Error code */
){
int i;
Pgno *aiAppend = db->pWorker->aiAppend;
LsmPgno *aiAppend = db->pWorker->aiAppend;
for(i=0; i<LSM_APPLIST_SZ; i++){
ckptAppend64(p, piOut, aiAppend[i], pRc);
+73 -68
View File
@@ -269,7 +269,7 @@ struct FileSystem {
struct Page {
u8 *aData; /* Buffer containing page data */
int nData; /* Bytes of usable data at aData[] */
Pgno iPg; /* Page number */
LsmPgno iPg; /* Page number */
int nRef; /* Number of outstanding references */
int flags; /* Combination of PAGE_XXX flags */
Page *pHashNext; /* Next page in hash table slot */
@@ -332,7 +332,7 @@ static int IOERR_WRAPPER(int rc){
#ifdef NDEBUG
# define assert_lists_are_ok(x)
#else
static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash);
static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash);
static void assert_lists_are_ok(FileSystem *pFS){
#if 0
@@ -532,7 +532,7 @@ int lsmFsCloseAndDeleteLog(FileSystem *pFS){
** Return true if page iReal of the database should be accessed using mmap.
** False otherwise.
*/
static int fsMmapPage(FileSystem *pFS, Pgno iReal){
static int fsMmapPage(FileSystem *pFS, LsmPgno iReal){
return ((i64)iReal*pFS->nPagesize <= pFS->nMapLimit);
}
@@ -540,7 +540,7 @@ static int fsMmapPage(FileSystem *pFS, Pgno iReal){
** Given that there are currently nHash slots in the hash table, return
** the hash key for file iFile, page iPg.
*/
static int fsHashKey(int nHash, Pgno iPg){
static int fsHashKey(int nHash, LsmPgno iPg){
return (iPg % nHash);
}
@@ -880,13 +880,13 @@ void lsmFsSetBlockSize(FileSystem *pFS, int nBlocksize){
** page on each block is the byte offset immediately following the 4-byte
** "previous block" pointer at the start of each block.
*/
static Pgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
Pgno iPg;
static LsmPgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
LsmPgno iPg;
if( pFS->pCompress ){
if( iBlock==1 ){
iPg = pFS->nMetasize * 2 + 4;
}else{
iPg = pFS->nBlocksize * (Pgno)(iBlock-1) + 4;
iPg = pFS->nBlocksize * (LsmPgno)(iBlock-1) + 4;
}
}else{
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
@@ -907,9 +907,9 @@ static Pgno fsFirstPageOnBlock(FileSystem *pFS, int iBlock){
** page on each block is the byte offset of the byte immediately before
** the 4-byte "next block" pointer at the end of each block.
*/
static Pgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
static LsmPgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
if( pFS->pCompress ){
return pFS->nBlocksize * (Pgno)iBlock - 1 - 4;
return pFS->nBlocksize * (LsmPgno)iBlock - 1 - 4;
}else{
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
return iBlock * nPagePerBlock;
@@ -920,7 +920,7 @@ static Pgno fsLastPageOnBlock(FileSystem *pFS, int iBlock){
** Return the block number of the block that page iPg is located on.
** Blocks are numbered starting from 1.
*/
static int fsPageToBlock(FileSystem *pFS, Pgno iPg){
static int fsPageToBlock(FileSystem *pFS, LsmPgno iPg){
if( pFS->pCompress ){
return (int)((iPg / pFS->nBlocksize) + 1);
}else{
@@ -933,7 +933,7 @@ static int fsPageToBlock(FileSystem *pFS, Pgno iPg){
**
** This function is only called in non-compressed database mode.
*/
static int fsIsLast(FileSystem *pFS, Pgno iPg){
static int fsIsLast(FileSystem *pFS, LsmPgno iPg){
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
assert( !pFS->pCompress );
return ( iPg && (iPg % nPagePerBlock)==0 );
@@ -944,7 +944,7 @@ static int fsIsLast(FileSystem *pFS, Pgno iPg){
**
** This function is only called in non-compressed database mode.
*/
static int fsIsFirst(FileSystem *pFS, Pgno iPg){
static int fsIsFirst(FileSystem *pFS, LsmPgno iPg){
const int nPagePerBlock = (pFS->nBlocksize / pFS->nPagesize);
assert( !pFS->pCompress );
return ( (iPg % nPagePerBlock)==1
@@ -967,7 +967,7 @@ u8 *lsmFsPageData(Page *pPage, int *pnData){
/*
** Return the page number of a page.
*/
Pgno lsmFsPageNumber(Page *pPage){
LsmPgno lsmFsPageNumber(Page *pPage){
/* assert( (pPage->flags & PAGE_DIRTY)==0 ); */
return pPage ? pPage->iPg : 0;
}
@@ -1058,7 +1058,7 @@ void lsmFsPurgeCache(FileSystem *pFS){
** Either way, if argument piHash is not NULL set *piHash to the hash slot
** number that page iPg would be stored in before returning.
*/
static Page *fsPageFindInHash(FileSystem *pFS, Pgno iPg, int *piHash){
static Page *fsPageFindInHash(FileSystem *pFS, LsmPgno iPg, int *piHash){
Page *p; /* Return value */
int iHash = fsHashKey(pFS->nHash, iPg);
@@ -1189,8 +1189,8 @@ static int fsRedirectBlock(Redirect *p, int iBlk){
** object passed as the second argument, return the destination page to
** which it is redirected. Otherwise, return a copy of iPg.
*/
Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
Pgno iReal = iPg;
LsmPgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, LsmPgno iPg){
LsmPgno iReal = iPg;
if( pRedir ){
const int nPagePerBlock = (
@@ -1203,7 +1203,7 @@ Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
if( iFrom>iBlk ) break;
if( iFrom==iBlk ){
int iTo = pRedir->a[i].iTo;
iReal = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
iReal = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
if( iTo==1 ){
iReal += (fsFirstPageOnBlock(pFS, 1)-1);
}
@@ -1217,7 +1217,7 @@ Pgno lsmFsRedirectPage(FileSystem *pFS, Redirect *pRedir, Pgno iPg){
}
/* Required by the circular fsBlockNext<->fsPageGet dependency. */
static int fsPageGet(FileSystem *, Segment *, Pgno, int, Page **, int *);
static int fsPageGet(FileSystem *, Segment *, LsmPgno, int, Page **, int *);
/*
** Parameter iBlock is a database file block. This function reads the value
@@ -1269,7 +1269,7 @@ static int fsBlockNext(
/*
** Return the page number of the last page on the same block as page iPg.
*/
Pgno fsLastPageOnPagesBlock(FileSystem *pFS, Pgno iPg){
LsmPgno fsLastPageOnPagesBlock(FileSystem *pFS, LsmPgno iPg){
return fsLastPageOnBlock(pFS, fsPageToBlock(pFS, iPg));
}
@@ -1537,7 +1537,7 @@ static int fsReadPagedata(
static int fsPageGet(
FileSystem *pFS, /* File-system handle */
Segment *pSeg, /* Block redirection to use (or NULL) */
Pgno iPg, /* Page id */
LsmPgno iPg, /* Page id */
int noContent, /* True to not load content from disk */
Page **ppPg, /* OUT: New page handle */
int *pnSpace /* OUT: Bytes of free space */
@@ -1549,7 +1549,7 @@ static int fsPageGet(
/* In most cases iReal is the same as iPg. Except, if pSeg->pRedirect is
** not NULL, and the block containing iPg has been redirected, then iReal
** is the page number after redirection. */
Pgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
LsmPgno iReal = lsmFsRedirectPage(pFS, (pSeg ? pSeg->pRedirect : 0), iPg);
assert_lists_are_ok(pFS);
assert( iPg>=fsFirstPageOnBlock(pFS, 1) );
@@ -1689,8 +1689,8 @@ int lsmFsReadSyncedId(lsm_db *db, int iMeta, i64 *piVal){
static int fsRunEndsBetween(
Segment *pRun,
Segment *pIgnore,
Pgno iFirst,
Pgno iLast
LsmPgno iFirst,
LsmPgno iLast
){
return (pRun!=pIgnore && (
(pRun->iFirst>=iFirst && pRun->iFirst<=iLast)
@@ -1705,8 +1705,8 @@ static int fsRunEndsBetween(
static int fsLevelEndsBetween(
Level *pLevel,
Segment *pIgnore,
Pgno iFirst,
Pgno iLast
LsmPgno iFirst,
LsmPgno iLast
){
int i;
@@ -1733,13 +1733,13 @@ static int fsFreeBlock(
int iBlk /* Block number of block to free */
){
int rc = LSM_OK; /* Return code */
Pgno iFirst; /* First page on block iBlk */
Pgno iLast; /* Last page on block iBlk */
LsmPgno iFirst; /* First page on block iBlk */
LsmPgno iLast; /* Last page on block iBlk */
Level *pLevel; /* Used to iterate through levels */
int iIn; /* Used to iterate through append points */
int iOut = 0; /* Used to output append points */
Pgno *aApp = pSnapshot->aiAppend;
LsmPgno *aApp = pSnapshot->aiAppend;
iFirst = fsFirstPageOnBlock(pFS, iBlk);
iLast = fsLastPageOnBlock(pFS, iBlk);
@@ -1811,11 +1811,16 @@ int lsmFsSortedDelete(
** number from the array that falls on block iBlk. Or, if none of the pages
** in aPgno[] fall on block iBlk, return 0.
*/
static Pgno firstOnBlock(FileSystem *pFS, int iBlk, Pgno *aPgno, int nPgno){
Pgno iRet = 0;
static LsmPgno firstOnBlock(
FileSystem *pFS,
int iBlk,
LsmPgno *aPgno,
int nPgno
){
LsmPgno iRet = 0;
int i;
for(i=0; i<nPgno; i++){
Pgno iPg = aPgno[i];
LsmPgno iPg = aPgno[i];
if( fsPageToBlock(pFS, iPg)==iBlk && (iRet==0 || iPg<iRet) ){
iRet = iPg;
}
@@ -1828,7 +1833,7 @@ static Pgno firstOnBlock(FileSystem *pFS, int iBlk, Pgno *aPgno, int nPgno){
** Return true if page iPg, which is a part of segment p, lies on
** a redirected block.
*/
static int fsPageRedirects(FileSystem *pFS, Segment *p, Pgno iPg){
static int fsPageRedirects(FileSystem *pFS, Segment *p, LsmPgno iPg){
return (iPg!=0 && iPg!=lsmFsRedirectPage(pFS, p->pRedirect, iPg));
}
@@ -1854,7 +1859,7 @@ static int fsSegmentRedirects(FileSystem *pFS, Segment *p){
void lsmFsGobble(
lsm_db *pDb,
Segment *pRun,
Pgno *aPgno,
LsmPgno *aPgno,
int nPgno
){
int rc = LSM_OK;
@@ -1871,7 +1876,7 @@ void lsmFsGobble(
while( rc==LSM_OK ){
int iNext = 0;
Pgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
LsmPgno iFirst = firstOnBlock(pFS, iBlk, aPgno, nPgno);
if( iFirst ){
pRun->iFirst = iFirst;
break;
@@ -1905,11 +1910,11 @@ void lsmFsGobble(
static int fsNextPageOffset(
FileSystem *pFS, /* File system object */
Segment *pSeg, /* Segment to move within */
Pgno iPg, /* Offset of current page */
LsmPgno iPg, /* Offset of current page */
int nByte, /* Size of current page including headers */
Pgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
LsmPgno *piNext /* OUT: Offset of next page. Or zero (EOF) */
){
Pgno iNext;
LsmPgno iNext;
int rc;
assert( pFS->pCompress );
@@ -1939,8 +1944,8 @@ static int fsNextPageOffset(
static int fsGetPageBefore(
FileSystem *pFS,
Segment *pSeg,
Pgno iPg,
Pgno *piPrev
LsmPgno iPg,
LsmPgno *piPrev
){
u8 aSz[3];
int rc;
@@ -1990,7 +1995,7 @@ static int fsGetPageBefore(
int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
int rc = LSM_OK;
FileSystem *pFS = pPg->pFS;
Pgno iPg = pPg->iPg;
LsmPgno iPg = pPg->iPg;
assert( 0==fsSegmentRedirects(pFS, pRun) );
if( pFS->pCompress ){
@@ -2062,10 +2067,10 @@ int lsmFsDbPageNext(Segment *pRun, Page *pPg, int eDir, Page **ppNext){
** start the new segment immediately following any segment that is part
** of the right-hand-side of pLvl.
*/
static Pgno findAppendPoint(FileSystem *pFS, Level *pLvl){
static LsmPgno findAppendPoint(FileSystem *pFS, Level *pLvl){
int i;
Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
Pgno iRet = 0;
LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
LsmPgno iRet = 0;
for(i=LSM_APPLIST_SZ-1; iRet==0 && i>=0; i--){
if( (iRet = aiAppend[i]) ){
@@ -2098,10 +2103,10 @@ int lsmFsSortedAppend(
){
int rc = LSM_OK;
Page *pPg = 0;
Pgno iApp = 0;
Pgno iNext = 0;
LsmPgno iApp = 0;
LsmPgno iNext = 0;
Segment *p = &pLvl->lhs;
Pgno iPrev = p->iLastPg;
LsmPgno iPrev = p->iLastPg;
*ppOut = 0;
assert( p->pRedirect==0 );
@@ -2195,7 +2200,7 @@ int lsmFsSortedFinish(FileSystem *pFS, Segment *p){
*/
if( fsLastPageOnPagesBlock(pFS, p->iLastPg)!=p->iLastPg ){
int i;
Pgno *aiAppend = pFS->pDb->pWorker->aiAppend;
LsmPgno *aiAppend = pFS->pDb->pWorker->aiAppend;
for(i=0; i<LSM_APPLIST_SZ; i++){
if( aiAppend[i]==0 ){
aiAppend[i] = p->iLastPg+1;
@@ -2226,7 +2231,7 @@ int lsmFsSortedFinish(FileSystem *pFS, Segment *p){
**
** Return LSM_OK if successful, or an lsm error code if an error occurs.
*/
int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, Pgno iPg, Page **ppPg){
int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, LsmPgno iPg, Page **ppPg){
return fsPageGet(pFS, pSeg, iPg, 0, ppPg, 0);
}
@@ -2238,7 +2243,7 @@ int lsmFsDbPageGet(FileSystem *pFS, Segment *pSeg, Pgno iPg, Page **ppPg){
*/
int lsmFsDbPageLast(FileSystem *pFS, Segment *pSeg, Page **ppPg){
int rc;
Pgno iPg = pSeg->iLastPg;
LsmPgno iPg = pSeg->iLastPg;
if( pFS->pCompress ){
int nSpace;
iPg++;
@@ -2366,14 +2371,14 @@ static void fsMovePage(
FileSystem *pFS, /* File system object */
int iTo, /* Destination block */
int iFrom, /* Source block */
Pgno *piPg /* IN/OUT: Page number */
LsmPgno *piPg /* IN/OUT: Page number */
){
Pgno iPg = *piPg;
LsmPgno iPg = *piPg;
if( iFrom==fsPageToBlock(pFS, iPg) ){
const int nPagePerBlock = (
pFS->pCompress ? pFS ->nBlocksize : (pFS->nBlocksize / pFS->nPagesize)
);
*piPg = iPg - (Pgno)(iFrom - iTo) * nPagePerBlock;
*piPg = iPg - (LsmPgno)(iFrom - iTo) * nPagePerBlock;
}
}
@@ -2457,21 +2462,21 @@ int lsmFsMoveBlock(FileSystem *pFS, Segment *pSeg, int iTo, int iFrom){
**
** This function is only used in compressed database mode.
*/
static Pgno fsAppendData(
static LsmPgno fsAppendData(
FileSystem *pFS, /* File-system handle */
Segment *pSeg, /* Segment to append to */
const u8 *aData, /* Buffer containing data to write */
int nData, /* Size of buffer aData[] in bytes */
int *pRc /* IN/OUT: Error code */
){
Pgno iRet = 0;
LsmPgno iRet = 0;
int rc = *pRc;
assert( pFS->pCompress );
if( rc==LSM_OK ){
int nRem = 0;
int nWrite = 0;
Pgno iLastOnBlock;
Pgno iApp = pSeg->iLastPg+1;
LsmPgno iLastOnBlock;
LsmPgno iApp = pSeg->iLastPg+1;
/* If this is the first data written into the segment, find an append-point
** or allocate a new block. */
@@ -2519,7 +2524,7 @@ static Pgno fsAppendData(
/* Set the "prev" pointer on the new block */
if( rc==LSM_OK ){
Pgno iWrite;
LsmPgno iWrite;
lsmPutU32(aPtr, fsPageToBlock(pFS, iApp));
iWrite = fsFirstPageOnBlock(pFS, iBlk);
rc = lsmEnvWrite(pFS->pEnv, pFS->fdDb, iWrite-4, aPtr, sizeof(aPtr));
@@ -2588,11 +2593,11 @@ static int fsCompressIntoBuffer(FileSystem *pFS, Page *pPg){
static int fsAppendPage(
FileSystem *pFS,
Segment *pSeg,
Pgno *piNew,
LsmPgno *piNew,
int *piPrev,
int *piNext
){
Pgno iPrev = pSeg->iLastPg;
LsmPgno iPrev = pSeg->iLastPg;
int rc;
assert( iPrev!=0 );
@@ -2650,7 +2655,7 @@ void lsmFsFlushWaiting(FileSystem *pFS, int *pRc){
/*
** If there exists a hash-table entry associated with page iPg, remove it.
*/
static void fsRemoveHashEntry(FileSystem *pFS, Pgno iPg){
static void fsRemoveHashEntry(FileSystem *pFS, LsmPgno iPg){
Page *p;
int iHash = fsHashKey(pFS->nHash, iPg);
@@ -2804,8 +2809,8 @@ int lsmFsSortedPadding(
){
int rc = LSM_OK;
if( pFS->pCompress && pSeg->iFirst ){
Pgno iLast2;
Pgno iLast = pSeg->iLastPg; /* Current last page of segment */
LsmPgno iLast2;
LsmPgno iLast = pSeg->iLastPg; /* Current last page of segment */
int nPad; /* Bytes of padding required */
u8 aSz[3];
@@ -2935,7 +2940,7 @@ int lsmFsSectorSize(FileSystem *pFS){
/*
** Helper function for lsmInfoArrayStructure().
*/
static Segment *startsWith(Segment *pRun, Pgno iFirst){
static Segment *startsWith(Segment *pRun, LsmPgno iFirst){
return (iFirst==pRun->iFirst) ? pRun : 0;
}
@@ -2943,7 +2948,7 @@ static Segment *startsWith(Segment *pRun, Pgno iFirst){
** Return the segment that starts with page iFirst, if any. If no such segment
** can be found, return NULL.
*/
static Segment *findSegment(Snapshot *pWorker, Pgno iFirst){
static Segment *findSegment(Snapshot *pWorker, LsmPgno iFirst){
Level *pLvl; /* Used to iterate through db levels */
Segment *pSeg = 0; /* Pointer to segment to return */
@@ -2970,7 +2975,7 @@ static Segment *findSegment(Snapshot *pWorker, Pgno iFirst){
int lsmInfoArrayStructure(
lsm_db *pDb,
int bBlock, /* True for block numbers only */
Pgno iFirst,
LsmPgno iFirst,
char **pzOut
){
int rc = LSM_OK;
@@ -3035,7 +3040,7 @@ int lsmInfoArrayStructure(
int lsmFsSegmentContainsPg(
FileSystem *pFS,
Segment *pSeg,
Pgno iPg,
LsmPgno iPg,
int *pbRes
){
Redirect *pRedir = pSeg->pRedirect;
@@ -3064,7 +3069,7 @@ int lsmFsSegmentContainsPg(
**
** If an error occurs, *pzOut is set to NULL and an LSM error code returned.
*/
int lsmInfoArrayPages(lsm_db *pDb, Pgno iFirst, char **pzOut){
int lsmInfoArrayPages(lsm_db *pDb, LsmPgno iFirst, char **pzOut){
int rc = LSM_OK;
Snapshot *pWorker; /* Worker snapshot */
Segment *pSeg = 0; /* Array to report on */
@@ -3297,7 +3302,7 @@ int lsmFsIntegrityCheck(lsm_db *pDb){
*/
int lsmFsDbPageIsLast(Segment *pSeg, Page *pPg){
if( pPg->pFS->pCompress ){
Pgno iNext = 0;
LsmPgno iNext = 0;
int rc;
rc = fsNextPageOffset(pPg->pFS, pSeg, pPg->iPg, pPg->nCompress+6, &iNext);
return (rc!=LSM_OK || iNext==0);
+3 -3
View File
@@ -583,14 +583,14 @@ int lsm_info(lsm_db *pDb, int eParam, ...){
}
case LSM_INFO_ARRAY_STRUCTURE: {
Pgno pgno = va_arg(ap, Pgno);
LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
rc = lsmInfoArrayStructure(pDb, 0, pgno, pzVal);
break;
}
case LSM_INFO_ARRAY_PAGES: {
Pgno pgno = va_arg(ap, Pgno);
LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
rc = lsmInfoArrayPages(pDb, pgno, pzVal);
break;
@@ -598,7 +598,7 @@ int lsm_info(lsm_db *pDb, int eParam, ...){
case LSM_INFO_PAGE_HEX_DUMP:
case LSM_INFO_PAGE_ASCII_DUMP: {
Pgno pgno = va_arg(ap, Pgno);
LsmPgno pgno = va_arg(ap, LsmPgno);
char **pzVal = va_arg(ap, char **);
int bUnlock = 0;
rc = infoGetWorker(pDb, 0, &bUnlock);
+80 -80
View File
@@ -104,9 +104,9 @@
#endif
typedef struct SegmentPtr SegmentPtr;
typedef struct Blob Blob;
typedef struct LsmBlob LsmBlob;
struct Blob {
struct LsmBlob {
lsm_env *pEnv;
void *pData;
int nData;
@@ -129,18 +129,18 @@ struct SegmentPtr {
Page *pPg; /* Current page */
u16 flags; /* Copy of page flags field */
int nCell; /* Number of cells on pPg */
Pgno iPtr; /* Base cascade pointer */
LsmPgno iPtr; /* Base cascade pointer */
/* Current cell. See segmentPtrLoadCell() */
int iCell; /* Current record within page pPg */
int eType; /* Type of current record */
Pgno iPgPtr; /* Cascade pointer offset */
LsmPgno iPgPtr; /* Cascade pointer offset */
void *pKey; int nKey; /* Key associated with current record */
void *pVal; int nVal; /* Current record value (eType==WRITE only) */
/* Blobs used to allocate buffers for pKey and pVal as required */
Blob blob1;
Blob blob2;
LsmBlob blob1;
LsmBlob blob2;
};
/*
@@ -171,10 +171,10 @@ struct BtreeCursor {
void *pKey;
int nKey;
int eType;
Pgno iPtr;
LsmPgno iPtr;
/* Storage for key, if not local */
Blob blob;
LsmBlob blob;
};
@@ -203,8 +203,8 @@ struct MultiCursor {
int flags; /* Mask of CURSOR_XXX flags */
int eType; /* Cache of current key type */
Blob key; /* Cache of current key (or NULL) */
Blob val; /* Cache of current value */
LsmBlob key; /* Cache of current key (or NULL) */
LsmBlob val; /* Cache of current value */
/* All the component cursors: */
TreeCursor *apTreeCsr[2]; /* Up to two tree cursors */
@@ -221,7 +221,7 @@ struct MultiCursor {
void *pSystemVal; /* Pointer to buffer to free */
/* Used by worker cursors only */
Pgno *pPrevMergePtr;
LsmPgno *pPrevMergePtr;
};
/*
@@ -295,11 +295,11 @@ struct MergeWorker {
Hierarchy hier; /* B-tree hierarchy under construction */
Page *pPage; /* Current output page */
int nWork; /* Number of calls to mergeWorkerNextPage() */
Pgno *aGobble; /* Gobble point for each input segment */
LsmPgno *aGobble; /* Gobble point for each input segment */
Pgno iIndirect;
LsmPgno iIndirect;
struct SavedPgno {
Pgno iPgno;
LsmPgno iPgno;
int bStore;
} aSave[2];
};
@@ -371,7 +371,7 @@ void lsmPutU64(u8 *aOut, u64 nVal){
aOut[7] = (u8)((nVal ) & 0xFF);
}
static int sortedBlobGrow(lsm_env *pEnv, Blob *pBlob, int nData){
static int sortedBlobGrow(lsm_env *pEnv, LsmBlob *pBlob, int nData){
assert( pBlob->pEnv==pEnv || (pBlob->pEnv==0 && pBlob->pData==0) );
if( pBlob->nAlloc<nData ){
pBlob->pData = lsmReallocOrFree(pEnv, pBlob->pData, nData);
@@ -382,7 +382,7 @@ static int sortedBlobGrow(lsm_env *pEnv, Blob *pBlob, int nData){
return LSM_OK;
}
static int sortedBlobSet(lsm_env *pEnv, Blob *pBlob, void *pData, int nData){
static int sortedBlobSet(lsm_env *pEnv, LsmBlob *pBlob, void *pData, int nData){
if( sortedBlobGrow(pEnv, pBlob, nData) ) return LSM_NOMEM;
memcpy(pBlob->pData, pData, nData);
pBlob->nData = nData;
@@ -390,15 +390,15 @@ static int sortedBlobSet(lsm_env *pEnv, Blob *pBlob, void *pData, int nData){
}
#if 0
static int sortedBlobCopy(Blob *pDest, Blob *pSrc){
static int sortedBlobCopy(LsmBlob *pDest, LsmBlob *pSrc){
return sortedBlobSet(pDest, pSrc->pData, pSrc->nData);
}
#endif
static void sortedBlobFree(Blob *pBlob){
static void sortedBlobFree(LsmBlob *pBlob){
assert( pBlob->pEnv || pBlob->pData==0 );
if( pBlob->pData ) lsmFree(pBlob->pEnv, pBlob->pData);
memset(pBlob, 0, sizeof(Blob));
memset(pBlob, 0, sizeof(LsmBlob));
}
static int sortedReadData(
@@ -407,7 +407,7 @@ static int sortedReadData(
int iOff,
int nByte,
void **ppData,
Blob *pBlob
LsmBlob *pBlob
){
int rc = LSM_OK;
int iEnd;
@@ -481,8 +481,8 @@ static int pageGetNRec(u8 *aData, int nData){
return (int)lsmGetU16(&aData[SEGMENT_NRECORD_OFFSET(nData)]);
}
static Pgno pageGetPtr(u8 *aData, int nData){
return (Pgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
static LsmPgno pageGetPtr(u8 *aData, int nData){
return (LsmPgno)lsmGetU64(&aData[SEGMENT_POINTER_OFFSET(nData)]);
}
static int pageGetFlags(u8 *aData, int nData){
@@ -506,8 +506,8 @@ static int pageObjGetNRec(Page *pPg){
** Return the decoded (possibly relative) pointer value stored in cell
** iCell from page aData/nData.
*/
static Pgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
Pgno iRet; /* Return value */
static LsmPgno pageGetRecordPtr(u8 *aData, int nData, int iCell){
LsmPgno iRet; /* Return value */
u8 *aCell; /* Pointer to cell iCell */
assert( iCell<pageGetNRec(aData, nData) && iCell>=0 );
@@ -522,7 +522,7 @@ static u8 *pageGetKey(
int iCell, /* Index of cell on page to read */
int *piTopic, /* OUT: Topic associated with this key */
int *pnKey, /* OUT: Size of key in bytes */
Blob *pBlob /* If required, use this for dynamic memory */
LsmBlob *pBlob /* If required, use this for dynamic memory */
){
u8 *pKey;
int nDummy;
@@ -554,7 +554,7 @@ static int pageGetKeyCopy(
Page *pPg, /* Page to read from */
int iCell, /* Index of cell on page to read */
int *piTopic, /* OUT: Topic associated with this key */
Blob *pBlob /* If required, use this for dynamic memory */
LsmBlob *pBlob /* If required, use this for dynamic memory */
){
int rc = LSM_OK;
int nKey;
@@ -569,8 +569,8 @@ static int pageGetKeyCopy(
return rc;
}
static Pgno pageGetBtreeRef(Page *pPg, int iKey){
Pgno iRef;
static LsmPgno pageGetBtreeRef(Page *pPg, int iKey){
LsmPgno iRef;
u8 *aData;
int nData;
u8 *aCell;
@@ -592,11 +592,11 @@ static int pageGetBtreeKey(
Segment *pSeg, /* Segment page pPg belongs to */
Page *pPg,
int iKey,
Pgno *piPtr,
LsmPgno *piPtr,
int *piTopic,
void **ppKey,
int *pnKey,
Blob *pBlob
LsmBlob *pBlob
){
u8 *aData;
int nData;
@@ -613,7 +613,7 @@ static int pageGetBtreeKey(
if( eType==0 ){
int rc;
Pgno iRef; /* Page number of referenced page */
LsmPgno iRef; /* Page number of referenced page */
Page *pRef;
aCell += GETVARINT64(aCell, iRef);
rc = lsmFsDbPageGet(lsmPageFS(pPg), pSeg, iRef, &pRef);
@@ -638,7 +638,7 @@ static int btreeCursorLoadKey(BtreeCursor *pCsr){
pCsr->nKey = 0;
pCsr->eType = 0;
}else{
Pgno dummy;
LsmPgno dummy;
int iPg = pCsr->iPg;
int iCell = pCsr->aPg[iPg].iCell;
while( iCell<0 && (--iPg)>=0 ){
@@ -683,7 +683,7 @@ static int btreeCursorNext(BtreeCursor *pCsr){
assert( pPg->iCell<=nCell );
pPg->iCell++;
if( pPg->iCell==nCell ){
Pgno iLoad;
LsmPgno iLoad;
/* Up to parent. */
lsmFsPageRelease(pPg->pPage);
@@ -842,7 +842,7 @@ static int btreeCursorRestore(
if( p->iPg ){
lsm_env *pEnv = lsmFsEnv(pCsr->pFS);
int iCell; /* Current cell number on leaf page */
Pgno iLeaf; /* Page number of current leaf page */
LsmPgno iLeaf; /* Page number of current leaf page */
int nDepth; /* Depth of b-tree structure */
Segment *pSeg = pCsr->pSeg;
@@ -866,7 +866,7 @@ static int btreeCursorRestore(
/* Populate any other aPg[] array entries */
if( rc==LSM_OK && nDepth>1 ){
Blob blob = {0,0,0};
LsmBlob blob = {0,0,0};
void *pSeek;
int nSeek;
int iTopicSeek;
@@ -883,7 +883,7 @@ static int btreeCursorRestore(
pSeek = 0;
nSeek = 0;
}else{
Pgno dummy;
LsmPgno dummy;
rc = pageGetBtreeKey(pSeg, pPg,
0, &dummy, &iTopicSeek, &pSeek, &nSeek, &pCsr->blob
);
@@ -912,7 +912,7 @@ static int btreeCursorRestore(
int iTry = (iMin+iMax)/2;
void *pKey; int nKey; /* Key for cell iTry */
int iTopic; /* Topic for key pKeyT/nKeyT */
Pgno iPtr; /* Pointer for cell iTry */
LsmPgno iPtr; /* Pointer for cell iTry */
int res; /* (pSeek - pKeyT) */
rc = pageGetBtreeKey(
@@ -955,7 +955,7 @@ static int btreeCursorRestore(
aData = fsPageData(pBtreePg->pPage, &nData);
pCsr->iPtr = btreeCursorPtr(aData, nData, pBtreePg->iCell+1);
if( pBtreePg->iCell<0 ){
Pgno dummy;
LsmPgno dummy;
int i;
for(i=pCsr->iPg-1; i>=0; i--){
if( pCsr->aPg[i].iCell>0 ) break;
@@ -1030,7 +1030,7 @@ static int segmentPtrReadData(
int iOff,
int nByte,
void **ppData,
Blob *pBlob
LsmBlob *pBlob
){
return sortedReadData(pPtr->pSeg, pPtr->pPg, iOff, nByte, ppData, pBlob);
}
@@ -1123,7 +1123,7 @@ static void sortedSplitkey(lsm_db *pDb, Level *pLevel, int *pRc){
}
if( rc==LSM_OK ){
int iTopic;
Blob blob = {0, 0, 0, 0};
LsmBlob blob = {0, 0, 0, 0};
u8 *aData;
int nData;
@@ -1131,7 +1131,7 @@ static void sortedSplitkey(lsm_db *pDb, Level *pLevel, int *pRc){
if( pageGetFlags(aData, nData) & SEGMENT_BTREE_FLAG ){
void *pKey;
int nKey;
Pgno dummy;
LsmPgno dummy;
rc = pageGetBtreeKey(pSeg,
pPg, pMerge->splitkey.iCell, &dummy, &iTopic, &pKey, &nKey, &blob
);
@@ -1342,7 +1342,7 @@ static int assertKeyLocation(
void *pKey, int nKey
){
lsm_env *pEnv = lsmFsEnv(pCsr->pDb->pFS);
Blob blob = {0, 0, 0};
LsmBlob blob = {0, 0, 0};
int eDir;
int iTopic = 0; /* TODO: Fix me */
@@ -1488,7 +1488,7 @@ static int ptrFwdPointer(
Page *pPage,
int iCell,
Segment *pSeg,
Pgno *piPtr,
LsmPgno *piPtr,
int *pbFound
){
Page *pPg = pPage;
@@ -1573,14 +1573,14 @@ static int sortedRhsFirst(MultiCursor *pCsr, Level *pLvl, SegmentPtr *pPtr){
static int segmentPtrFwdPointer(
MultiCursor *pCsr, /* Multi-cursor pPtr belongs to */
SegmentPtr *pPtr, /* Segment-pointer to extract FC ptr from */
Pgno *piPtr /* OUT: FC pointer value */
LsmPgno *piPtr /* OUT: FC pointer value */
){
Level *pLvl = pPtr->pLevel;
Level *pNext = pLvl->pNext;
Page *pPg = pPtr->pPg;
int rc;
int bFound;
Pgno iOut = 0;
LsmPgno iOut = 0;
if( pPtr->pSeg==&pLvl->lhs || pPtr->pSeg==&pLvl->aRhs[pLvl->nRight-1] ){
if( pNext==0
@@ -1641,7 +1641,7 @@ static int segmentPtrSeek(
int rc = LSM_OK;
int iMin;
int iMax;
Pgno iPtrOut = 0;
LsmPgno iPtrOut = 0;
/* If the current page contains an oversized entry, then there are no
** pointers to one or more of the subsequent pages in the sorted run.
@@ -1768,18 +1768,18 @@ static int seekInBtree(
Segment *pSeg, /* Seek within this segment */
int iTopic,
void *pKey, int nKey, /* Key to seek to */
Pgno *aPg, /* OUT: Page numbers */
LsmPgno *aPg, /* OUT: Page numbers */
Page **ppPg /* OUT: Leaf (sorted-run) page reference */
){
int i = 0;
int rc;
int iPg;
Page *pPg = 0;
Blob blob = {0, 0, 0};
LsmBlob blob = {0, 0, 0};
iPg = (int)pSeg->iRoot;
do {
Pgno *piFirst = 0;
LsmPgno *piFirst = 0;
if( aPg ){
aPg[i++] = iPg;
piFirst = &aPg[i];
@@ -1808,7 +1808,7 @@ static int seekInBtree(
int iTry = (iMin+iMax)/2;
void *pKeyT; int nKeyT; /* Key for cell iTry */
int iTopicT; /* Topic for key pKeyT/nKeyT */
Pgno iPtr; /* Pointer associated with cell iTry */
LsmPgno iPtr; /* Pointer associated with cell iTry */
int res; /* (pKey - pKeyT) */
rc = pageGetBtreeKey(
@@ -1899,7 +1899,7 @@ static int seekInLevel(
int eSeek, /* Search bias - see above */
int iTopic, /* Key topic to search for */
void *pKey, int nKey, /* Key to search for */
Pgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
LsmPgno *piPgno, /* IN/OUT: fraction cascade pointer (or 0) */
int *pbStop /* OUT: See above */
){
Level *pLvl = aPtr[0].pLevel; /* Level to seek within */
@@ -3055,7 +3055,7 @@ int lsmMCursorSeek(
int bStop = 0; /* Set to true to halt search operation */
int rc = LSM_OK; /* Return code */
int iPtr = 0; /* Used to iterate through pCsr->aPtr[] */
Pgno iPgno = 0; /* FC pointer value */
LsmPgno iPgno = 0; /* FC pointer value */
assert( pCsr->apTreeCsr[0]==0 || iTopic==0 );
assert( pCsr->apTreeCsr[1]==0 || iTopic==0 );
@@ -3537,7 +3537,7 @@ static int mergeWorkerLoadHierarchy(MergeWorker *pMW){
** + Type byte (always SORTED_SEPARATOR or SORTED_SYSTEM_SEPARATOR),
** + Absolute pointer value (varint),
** + Number of bytes in key (varint),
** + Blob containing key data.
** + LsmBlob containing key data.
**
** 2. All pointer values are stored as absolute values (not offsets
** relative to the footer pointer value).
@@ -3571,8 +3571,8 @@ static int mergeWorkerLoadHierarchy(MergeWorker *pMW){
static int mergeWorkerBtreeWrite(
MergeWorker *pMW,
u8 eType,
Pgno iPtr,
Pgno iKeyPg,
LsmPgno iPtr,
LsmPgno iKeyPg,
void *pKey,
int nKey
){
@@ -3682,7 +3682,7 @@ static int mergeWorkerBtreeWrite(
static int mergeWorkerBtreeIndirect(MergeWorker *pMW){
int rc = LSM_OK;
if( pMW->iIndirect ){
Pgno iKeyPg = pMW->aSave[1].iPgno;
LsmPgno iKeyPg = pMW->aSave[1].iPgno;
rc = mergeWorkerBtreeWrite(pMW, 0, pMW->iIndirect, iKeyPg, 0, 0);
pMW->iIndirect = 0;
}
@@ -3703,7 +3703,7 @@ static int mergeWorkerPushHierarchy(
int nKey /* Size of pKey buffer in bytes */
){
int rc = LSM_OK; /* Return Code */
Pgno iPtr; /* Pointer value to accompany pKey/nKey */
LsmPgno iPtr; /* Pointer value to accompany pKey/nKey */
assert( pMW->aSave[0].bStore==0 );
assert( pMW->aSave[1].bStore==0 );
@@ -3734,7 +3734,7 @@ static int mergeWorkerFinishHierarchy(
){
int i; /* Used to loop through apHier[] */
int rc = LSM_OK; /* Return code */
Pgno iPtr; /* New right-hand-child pointer value */
LsmPgno iPtr; /* New right-hand-child pointer value */
iPtr = pMW->aSave[0].iPgno;
for(i=0; i<pMW->hier.nHier && rc==LSM_OK; i++){
@@ -3830,7 +3830,7 @@ static int mergeWorkerPersistAndRelease(MergeWorker *pMW){
*/
static int mergeWorkerNextPage(
MergeWorker *pMW, /* Merge worker object to append page to */
Pgno iFPtr /* Pointer value for footer of new page */
LsmPgno iFPtr /* Pointer value for footer of new page */
){
int rc = LSM_OK; /* Return code */
Page *pNext = 0; /* New page appended to run */
@@ -4218,7 +4218,7 @@ static int mergeWorkerStep(MergeWorker *pMW){
int rc = LSM_OK; /* Return code */
int eType; /* SORTED_SEPARATOR, WRITE or DELETE */
void *pKey; int nKey; /* Key */
Pgno iPtr;
LsmPgno iPtr;
int iVal;
pCsr = pMW->pCsr;
@@ -4371,7 +4371,7 @@ static int sortedNewToplevel(
if( rc!=LSM_OK ){
lsmMCursorClose(pCsr, 0);
}else{
Pgno iLeftPtr = 0;
LsmPgno iLeftPtr = 0;
Merge merge; /* Merge object used to create new level */
MergeWorker mergeworker; /* MergeWorker object for the same purpose */
@@ -4548,7 +4548,7 @@ static int mergeWorkerInit(
memset(pMW, 0, sizeof(MergeWorker));
pMW->pDb = pDb;
pMW->pLevel = pLevel;
pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno) * pLevel->nRight, &rc);
pMW->aGobble = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*pLevel->nRight,&rc);
/* Create a multi-cursor to read the data to write to the new
** segment. The new segment contains:
@@ -4630,7 +4630,7 @@ static int sortedBtreeGobble(
int rc = LSM_OK;
if( rtTopic(pCsr->eType)==0 ){
Segment *pSeg = pCsr->aPtr[iGobble].pSeg;
Pgno *aPg;
LsmPgno *aPg;
int nPg;
/* Seek from the root of the b-tree to the segment leaf that may contain
@@ -4639,7 +4639,7 @@ static int sortedBtreeGobble(
** gobbled up to (but not including) the first of these page numbers.
*/
assert( pSeg->iRoot>0 );
aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(Pgno)*32, &rc);
aPg = lsmMallocZeroRc(pDb->pEnv, sizeof(LsmPgno)*32, &rc);
if( rc==LSM_OK ){
rc = seekInBtree(pCsr, pSeg,
rtTopic(pCsr->eType), pCsr->key.pData, pCsr->key.nData, aPg, 0
@@ -5466,9 +5466,9 @@ int lsmFlushTreeToDisk(lsm_db *pDb){
*/
static char *segToString(lsm_env *pEnv, Segment *pSeg, int nMin){
int nSize = pSeg->nSize;
Pgno iRoot = pSeg->iRoot;
Pgno iFirst = pSeg->iFirst;
Pgno iLast = pSeg->iLastPg;
LsmPgno iRoot = pSeg->iRoot;
LsmPgno iFirst = pSeg->iFirst;
LsmPgno iLast = pSeg->iLastPg;
char *z;
char *z1;
@@ -5527,7 +5527,7 @@ static int fileToString(
}
void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){
Blob blob = {0, 0, 0}; /* Blob used for keys */
LsmBlob blob = {0, 0, 0}; /* LsmBlob used for keys */
LsmString s;
int i;
@@ -5563,7 +5563,7 @@ void sortedDumpPage(lsm_db *pDb, Segment *pRun, Page *pPg, int bVals){
aCell += lsmVarintGet32(aCell, &iPgPtr);
if( eType==0 ){
Pgno iRef; /* Page number of referenced page */
LsmPgno iRef; /* Page number of referenced page */
aCell += lsmVarintGet64(aCell, &iRef);
lsmFsDbPageGet(pDb->pFS, pRun, iRef, &pRef);
aKey = pageGetKey(pRun, pRef, 0, &iTopic, &nKey, &blob);
@@ -5607,7 +5607,7 @@ static void infoCellDump(
int *piPgPtr,
u8 **paKey, int *pnKey,
u8 **paVal, int *pnVal,
Blob *pBlob
LsmBlob *pBlob
){
u8 *aData; int nData; /* Page data */
u8 *aKey; int nKey = 0; /* Key */
@@ -5625,7 +5625,7 @@ static void infoCellDump(
if( eType==0 ){
int dummy;
Pgno iRef; /* Page number of referenced page */
LsmPgno iRef; /* Page number of referenced page */
aCell += lsmVarintGet64(aCell, &iRef);
if( bIndirect ){
lsmFsDbPageGet(pDb->pFS, pSeg, iRef, &pRef);
@@ -5671,7 +5671,7 @@ static int infoAppendBlob(LsmString *pStr, int bHex, u8 *z, int n){
static int infoPageDump(
lsm_db *pDb, /* Database handle */
Pgno iPg, /* Page number of page to dump */
LsmPgno iPg, /* Page number of page to dump */
int flags,
char **pzOut /* OUT: lsmMalloc'd string */
){
@@ -5712,7 +5712,7 @@ static int infoPageDump(
}
if( rc==LSM_OK ){
Blob blob = {0, 0, 0, 0};
LsmBlob blob = {0, 0, 0, 0};
int nKeyWidth = 0;
LsmString str;
int nRec;
@@ -5747,7 +5747,7 @@ static int infoPageDump(
u8 *aVal; int nVal = 0; /* Value */
int iPgPtr;
int eType;
Pgno iAbsPtr;
LsmPgno iAbsPtr;
char zFlags[8];
infoCellDump(pDb, pSeg, bIndirect, pPg, iCell, &eType, &iPgPtr,
@@ -5813,7 +5813,7 @@ static int infoPageDump(
int lsmInfoPageDump(
lsm_db *pDb, /* Database handle */
Pgno iPg, /* Page number of page to dump */
LsmPgno iPg, /* Page number of page to dump */
int bHex, /* True to output key/value in hex form */
char **pzOut /* OUT: lsmMalloc'd string */
){
@@ -5989,8 +5989,8 @@ void lsmSortedExpandBtreePage(Page *pPg, int nOrig){
#ifdef LSM_DEBUG_EXPENSIVE
static void assertRunInOrder(lsm_db *pDb, Segment *pSeg){
Page *pPg = 0;
Blob blob1 = {0, 0, 0, 0};
Blob blob2 = {0, 0, 0, 0};
LsmBlob blob1 = {0, 0, 0, 0};
LsmBlob blob2 = {0, 0, 0, 0};
lsmFsDbPageGet(pDb->pFS, pSeg, pSeg->iFirst, &pPg);
while( pPg ){
@@ -6052,7 +6052,7 @@ static int assertPointersOk(
int rc = LSM_OK; /* Error code */
SegmentPtr ptr1; /* Iterates through pOne */
SegmentPtr ptr2; /* Iterates through pTwo */
Pgno iPrev;
LsmPgno iPrev;
assert( pOne && pTwo );
@@ -6075,7 +6075,7 @@ static int assertPointersOk(
}
while( rc==LSM_OK && ptr2.pPg ){
Pgno iThis;
LsmPgno iThis;
/* Advance to the next page of segment pTwo that contains at least
** one cell. Break out of the loop if the iterator reaches EOF. */
@@ -6137,7 +6137,7 @@ static int assertBtreeOk(
){
int rc = LSM_OK; /* Return code */
if( pSeg->iRoot ){
Blob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
LsmBlob blob = {0, 0, 0}; /* Buffer used to cache overflow keys */
FileSystem *pFS = pDb->pFS; /* File system to read from */
Page *pPg = 0; /* Main run page */
BtreeCursor *pCsr = 0; /* Btree cursor */
+88
View File
@@ -0,0 +1,88 @@
#!/bin/sh
# restart with tclsh \
exec tclsh "$0" "$@"
set srcdir [file dirname [file dirname [info script]]]
set G(src) [string map [list %dir% $srcdir] {
%dir%/lsm.h
%dir%/lsmInt.h
%dir%/lsm_vtab.c
%dir%/lsm_ckpt.c
%dir%/lsm_file.c
%dir%/lsm_log.c
%dir%/lsm_main.c
%dir%/lsm_mem.c
%dir%/lsm_mutex.c
%dir%/lsm_shared.c
%dir%/lsm_sorted.c
%dir%/lsm_str.c
%dir%/lsm_tree.c
%dir%/lsm_unix.c
%dir%/lsm_varint.c
%dir%/lsm_win32.c
}]
set G(hdr) {
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_LSM1)
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG 1
#endif
#if defined(NDEBUG) && defined(SQLITE_DEBUG)
# undef NDEBUG
#endif
}
set G(footer) {
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_LSM1) */
}
#-------------------------------------------------------------------------
# Read and return the entire contents of text file $zFile from disk.
#
proc readfile {zFile} {
set fd [open $zFile]
set data [read $fd]
close $fd
return $data
}
proc lsm1c_init {zOut} {
global G
set G(fd) stdout
set G(fd) [open $zOut w]
puts -nonewline $G(fd) $G(hdr)
}
proc lsm1c_printfile {zIn} {
global G
set data [readfile $zIn]
set zTail [file tail $zIn]
puts $G(fd) "#line 1 \"$zTail\""
foreach line [split $data "\n"] {
if {[regexp {^# *include.*lsm} $line]} {
set line "/* $line */"
} elseif { [regexp {^(const )?[a-zA-Z][a-zA-Z0-9]* [*]?lsm[^_]} $line] } {
set line "static $line"
}
puts $G(fd) $line
}
}
proc lsm1c_close {} {
global G
puts -nonewline $G(fd) $G(footer)
if {$G(fd)!="stdout"} {
close $G(fd)
}
}
lsm1c_init lsm1.c
foreach f $G(src) { lsm1c_printfile $f }
lsm1c_close
+3 -3
View File
@@ -47,9 +47,9 @@ static void rot13func(
const unsigned char *zIn;
int nIn;
unsigned char *zOut;
char *zToFree = 0;
unsigned char *zToFree = 0;
int i;
char zTemp[100];
unsigned char zTemp[100];
assert( argc==1 );
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
zIn = (const unsigned char*)sqlite3_value_text(argv[0]);
@@ -57,7 +57,7 @@ static void rot13func(
if( nIn<sizeof(zTemp)-1 ){
zOut = zTemp;
}else{
zOut = zToFree = sqlite3_malloc( nIn+1 );
zOut = zToFree = (unsigned char*)sqlite3_malloc64( nIn+1 );
if( zOut==0 ){
sqlite3_result_error_nomem(context);
return;
+276 -29
View File
@@ -56,6 +56,8 @@
**
** SWARMVTAB
**
** LEGACY SYNTAX:
**
** A "swarmvtab" virtual table is created similarly to a unionvtab table:
**
** CREATE VIRTUAL TABLE <name>
@@ -66,13 +68,78 @@
** the database file containing the source table. The <callback> option
** is optional. If included, it is the name of an application-defined
** SQL function that is invoked with the URI of the file, if the file
** does not already exist on disk.
** does not already exist on disk when required by swarmvtab.
**
** NEW SYNTAX:
**
** Using the new syntax, a swarmvtab table is created with:
**
** CREATE VIRTUAL TABLE <name> USING swarmvtab(
** <sql-statement> [, <options>]
** );
**
** where valid <options> are:
**
** missing=<udf-function-name>
** openclose=<udf-function-name>
** maxopen=<integer>
** <sql-parameter>=<text-value>
**
** The <sql-statement> must return the same 4 columns as for a swarmvtab
** table in legacy mode. However, it may also return a 5th column - the
** "context" column. The text value returned in this column is not used
** at all by the swarmvtab implementation, except that it is passed as
** an additional argument to the two UDF functions that may be invoked
** (see below).
**
** The "missing" option, if present, specifies the name of an SQL UDF
** function to be invoked if a database file is not already present on
** disk when required by swarmvtab. If the <sql-statement> did not provide
** a context column, it is invoked as:
**
** SELECT <missing-udf>(<database filename/uri>);
**
** Or, if there was a context column:
**
** SELECT <missing-udf>(<database filename/uri>, <context>);
**
** The "openclose" option may also specify a UDF function. This function
** is invoked right before swarmvtab opens a database, and right after
** it closes one. The first argument - or first two arguments, if
** <sql-statement> supplied the context column - is the same as for
** the "missing" UDF. Following this, the UDF is passed integer value
** 0 before a db is opened, and 1 right after it is closed. If both
** a missing and openclose UDF is supplied, the application should expect
** the following sequence of calls (for a single database):
**
** SELECT <openclose-udf>(<db filename>, <context>, 0);
** if( db not already on disk ){
** SELECT <missing-udf>(<db filename>, <context>);
** }
** ... swarmvtab uses database ...
** SELECT <openclose-udf>(<db filename>, <context>, 1);
**
** The "maxopen" option is used to configure the maximum number of
** database files swarmvtab will hold open simultaneously (default 9).
**
** If an option name begins with a ":" character, then it is assumed
** to be an SQL parameter. In this case, the specified text value is
** bound to the same variable of the <sql-statement> before it is
** executed. It is an error of the named SQL parameter does not exist.
** For example:
**
** CREATE VIRTUAL TABLE swarm USING swarmvtab(
** 'SELECT :path || localfile, tbl, min, max FROM swarmdir',
** :path='/home/user/databases/'
** missing='missing_func'
** );
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -128,6 +195,7 @@ struct UnionSrc {
/* Fields used by swarmvtab only */
char *zFile; /* Database file containing table zTab */
char *zContext; /* Context string, if any */
int nUser; /* Current number of users */
sqlite3 *db; /* Database handle */
UnionSrc *pNextClosable; /* Next in list of closable sources */
@@ -145,8 +213,11 @@ struct UnionTab {
UnionSrc *aSrc; /* Array of source tables, sorted by rowid */
/* Used by swarmvtab only */
int bHasContext; /* Has context strings */
char *zSourceStr; /* Expected unionSourceToStr() value */
char *zNotFoundCallback; /* UDF to invoke if file not found on open */
sqlite3_stmt *pNotFound; /* UDF to invoke if file not found on open */
sqlite3_stmt *pOpenClose; /* UDF to invoke on open and close */
UnionSrc *pClosable; /* First in list of closable sources */
int nOpen; /* Current number of open sources */
int nMaxOpen; /* Maximum number of open sources */
@@ -351,6 +422,39 @@ static void unionFinalize(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
}
}
/*
** If an "openclose" UDF was supplied when this virtual table was created,
** invoke it now. The first argument passed is the name of the database
** file for source pSrc. The second is integer value bClose.
**
** If successful, return SQLITE_OK. Otherwise an SQLite error code. In this
** case if argument pzErr is not NULL, also set (*pzErr) to an English
** language error message. The caller is responsible for eventually freeing
** any error message using sqlite3_free().
*/
static int unionInvokeOpenClose(
UnionTab *pTab,
UnionSrc *pSrc,
int bClose,
char **pzErr
){
int rc = SQLITE_OK;
if( pTab->pOpenClose ){
sqlite3_bind_text(pTab->pOpenClose, 1, pSrc->zFile, -1, SQLITE_STATIC);
if( pTab->bHasContext ){
sqlite3_bind_text(pTab->pOpenClose, 2, pSrc->zContext, -1, SQLITE_STATIC);
}
sqlite3_bind_int(pTab->pOpenClose, 2+pTab->bHasContext, bClose);
sqlite3_step(pTab->pOpenClose);
if( SQLITE_OK!=(rc = sqlite3_reset(pTab->pOpenClose)) ){
if( pzErr ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
}
}
}
return rc;
}
/*
** This function is a no-op for unionvtab. For swarmvtab, it attempts to
** close open database files until at most nMax are open. An SQLite error
@@ -358,13 +462,16 @@ static void unionFinalize(int *pRc, sqlite3_stmt *pStmt, char **pzErr){
*/
static void unionCloseSources(UnionTab *pTab, int nMax){
while( pTab->pClosable && pTab->nOpen>nMax ){
UnionSrc *p;
UnionSrc **pp;
for(pp=&pTab->pClosable; (*pp)->pNextClosable; pp=&(*pp)->pNextClosable);
assert( (*pp)->db );
sqlite3_close((*pp)->db);
(*pp)->db = 0;
p = *pp;
assert( p->db );
sqlite3_close(p->db);
p->db = 0;
*pp = 0;
pTab->nOpen--;
unionInvokeOpenClose(pTab, p, 1, 0);
}
}
@@ -377,13 +484,18 @@ static int unionDisconnect(sqlite3_vtab *pVtab){
int i;
for(i=0; i<pTab->nSrc; i++){
UnionSrc *pSrc = &pTab->aSrc[i];
if( pSrc->db ){
unionInvokeOpenClose(pTab, pSrc, 1, 0);
}
sqlite3_free(pSrc->zDb);
sqlite3_free(pSrc->zTab);
sqlite3_free(pSrc->zFile);
sqlite3_free(pSrc->zContext);
sqlite3_close(pSrc->db);
}
sqlite3_finalize(pTab->pNotFound);
sqlite3_finalize(pTab->pOpenClose);
sqlite3_free(pTab->zSourceStr);
sqlite3_free(pTab->zNotFoundCallback);
sqlite3_free(pTab->aSrc);
sqlite3_free(pTab);
}
@@ -496,29 +608,31 @@ static int unionSourceCheck(UnionTab *pTab, char **pzErr){
return rc;
}
/*
** Try to open the swarmvtab database. If initially unable, invoke the
** not-found callback UDF and then try again.
*/
static int unionOpenDatabaseInner(UnionTab *pTab, UnionSrc *pSrc, char **pzErr){
int rc = SQLITE_OK;
static const int openFlags =
SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
static const int openFlags = SQLITE_OPEN_READONLY | SQLITE_OPEN_URI;
int rc;
rc = unionInvokeOpenClose(pTab, pSrc, 0, pzErr);
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
if( rc==SQLITE_OK ) return rc;
if( pTab->zNotFoundCallback ){
char *zSql = sqlite3_mprintf("SELECT \"%w\"(%Q);",
pTab->zNotFoundCallback, pSrc->zFile);
if( pTab->pNotFound ){
sqlite3_close(pSrc->db);
pSrc->db = 0;
if( zSql==0 ){
*pzErr = sqlite3_mprintf("out of memory");
return SQLITE_NOMEM;
sqlite3_bind_text(pTab->pNotFound, 1, pSrc->zFile, -1, SQLITE_STATIC);
if( pTab->bHasContext ){
sqlite3_bind_text(pTab->pNotFound, 2, pSrc->zContext, -1, SQLITE_STATIC);
}
sqlite3_step(pTab->pNotFound);
if( SQLITE_OK!=(rc = sqlite3_reset(pTab->pNotFound)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(pTab->db));
return rc;
}
rc = sqlite3_exec(pTab->db, zSql, 0, 0, pzErr);
sqlite3_free(zSql);
if( rc ) return rc;
rc = sqlite3_open_v2(pSrc->zFile, &pSrc->db, openFlags, 0);
}
if( rc!=SQLITE_OK ){
@@ -572,6 +686,7 @@ static int unionOpenDatabase(UnionTab *pTab, int iSrc, char **pzErr){
}else{
sqlite3_close(pSrc->db);
pSrc->db = 0;
unionInvokeOpenClose(pTab, pSrc, 1, 0);
}
}
@@ -627,6 +742,132 @@ static int unionFinalizeCsrStmt(UnionCsr *pCsr){
return rc;
}
/*
** Return true if the argument is a space, tab, CR or LF character.
*/
static int union_isspace(char c){
return (c==' ' || c=='\n' || c=='\r' || c=='\t');
}
/*
** Return true if the argument is an alphanumeric character in the
** ASCII range.
*/
static int union_isidchar(char c){
return ((c>='a' && c<='z') || (c>='A' && c<'Z') || (c>='0' && c<='9'));
}
/*
** This function is called to handle all arguments following the first
** (the SQL statement) passed to a swarmvtab (not unionvtab) CREATE
** VIRTUAL TABLE statement. It may bind parameters to the SQL statement
** or configure members of the UnionTab object passed as the second
** argument.
**
** Refer to header comments at the top of this file for a description
** of the arguments parsed.
**
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, if an error occurs, *pRc is set to an SQLite error
** code. In this case *pzErr may be set to point to a buffer containing
** an English language error message. It is the responsibility of the
** caller to eventually free the buffer using sqlite3_free().
*/
static void unionConfigureVtab(
int *pRc, /* IN/OUT: Error code */
UnionTab *pTab, /* Table to configure */
sqlite3_stmt *pStmt, /* SQL statement to find sources */
int nArg, /* Number of entries in azArg[] array */
const char * const *azArg, /* Array of arguments to consider */
char **pzErr /* OUT: Error message */
){
int rc = *pRc;
int i;
if( rc==SQLITE_OK ){
pTab->bHasContext = (sqlite3_column_count(pStmt)>4);
}
for(i=0; rc==SQLITE_OK && i<nArg; i++){
char *zArg = unionStrdup(&rc, azArg[i]);
if( zArg ){
int nOpt = 0; /* Size of option name in bytes */
char *zOpt; /* Pointer to option name */
char *zVal; /* Pointer to value */
unionDequote(zArg);
zOpt = zArg;
while( union_isspace(*zOpt) ) zOpt++;
zVal = zOpt;
if( *zVal==':' ) zVal++;
while( union_isidchar(*zVal) ) zVal++;
nOpt = zVal-zOpt;
while( union_isspace(*zVal) ) zVal++;
if( *zVal=='=' ){
zOpt[nOpt] = '\0';
zVal++;
while( union_isspace(*zVal) ) zVal++;
zVal = unionStrdup(&rc, zVal);
if( zVal ){
unionDequote(zVal);
if( zOpt[0]==':' ){
/* A value to bind to the SQL statement */
int iParam = sqlite3_bind_parameter_index(pStmt, zOpt);
if( iParam==0 ){
*pzErr = sqlite3_mprintf(
"swarmvtab: no such SQL parameter: %s", zOpt
);
rc = SQLITE_ERROR;
}else{
rc = sqlite3_bind_text(pStmt, iParam, zVal, -1, SQLITE_TRANSIENT);
}
}else if( nOpt==7 && 0==sqlite3_strnicmp(zOpt, "maxopen", 7) ){
pTab->nMaxOpen = atoi(zVal);
if( pTab->nMaxOpen<=0 ){
*pzErr = sqlite3_mprintf("swarmvtab: illegal maxopen value");
rc = SQLITE_ERROR;
}
}else if( nOpt==7 && 0==sqlite3_strnicmp(zOpt, "missing", 7) ){
if( pTab->pNotFound ){
*pzErr = sqlite3_mprintf(
"swarmvtab: duplicate \"missing\" option");
rc = SQLITE_ERROR;
}else{
pTab->pNotFound = unionPreparePrintf(&rc, pzErr, pTab->db,
"SELECT \"%w\"(?%s)", zVal, pTab->bHasContext ? ",?" : ""
);
}
}else if( nOpt==9 && 0==sqlite3_strnicmp(zOpt, "openclose", 9) ){
if( pTab->pOpenClose ){
*pzErr = sqlite3_mprintf(
"swarmvtab: duplicate \"openclose\" option");
rc = SQLITE_ERROR;
}else{
pTab->pOpenClose = unionPreparePrintf(&rc, pzErr, pTab->db,
"SELECT \"%w\"(?,?%s)", zVal, pTab->bHasContext ? ",?" : ""
);
}
}else{
*pzErr = sqlite3_mprintf("swarmvtab: unrecognized option: %s",zOpt);
rc = SQLITE_ERROR;
}
sqlite3_free(zVal);
}
}else{
if( i==0 && nArg==1 ){
pTab->pNotFound = unionPreparePrintf(&rc, pzErr, pTab->db,
"SELECT \"%w\"(?)", zArg
);
}else{
*pzErr = sqlite3_mprintf( "swarmvtab: parse error: %s", azArg[i]);
rc = SQLITE_ERROR;
}
}
sqlite3_free(zArg);
}
}
*pRc = rc;
}
/*
** xConnect/xCreate method.
**
@@ -654,7 +895,7 @@ static int unionConnect(
/* unionvtab tables may only be created in the temp schema */
*pzErr = sqlite3_mprintf("%s tables must be created in TEMP schema", zVtab);
rc = SQLITE_ERROR;
}else if( argc!=4 && argc!=5 ){
}else if( argc<4 || (argc>4 && bSwarm==0) ){
*pzErr = sqlite3_mprintf("wrong number of arguments for %s", zVtab);
rc = SQLITE_ERROR;
}else{
@@ -673,6 +914,17 @@ static int unionConnect(
/* Allocate the UnionTab structure */
pTab = unionMalloc(&rc, sizeof(UnionTab));
if( pTab ){
assert( rc==SQLITE_OK );
pTab->db = db;
pTab->bSwarm = bSwarm;
pTab->nMaxOpen = SWARMVTAB_MAX_OPEN;
}
/* Parse other CVT arguments, if any */
if( bSwarm ){
unionConfigureVtab(&rc, pTab, pStmt, argc-4, &argv[4], pzErr);
}
/* Iterate through the rows returned by the SQL statement specified
** as an argument to the CREATE VIRTUAL TABLE statement. */
@@ -715,17 +967,15 @@ static int unionConnect(
}else{
pSrc->zDb = unionStrdup(&rc, zDb);
}
if( pTab->bHasContext ){
const char *zContext = (const char*)sqlite3_column_text(pStmt, 4);
pSrc->zContext = unionStrdup(&rc, zContext);
}
}
}
unionFinalize(&rc, pStmt, pzErr);
pStmt = 0;
/* Capture the not-found callback UDF name */
if( rc==SQLITE_OK && argc>=5 ){
pTab->zNotFoundCallback = unionStrdup(&rc, argv[4]);
unionDequote(pTab->zNotFoundCallback);
}
/* It is an error if the SELECT statement returned zero rows. If only
** because there is no way to determine the schema of the virtual
** table in this case. */
@@ -738,9 +988,6 @@ static int unionConnect(
** compatible schemas. For swarmvtab, attach the first database and
** check that the first table is a rowid table only. */
if( rc==SQLITE_OK ){
pTab->db = db;
pTab->bSwarm = bSwarm;
pTab->nMaxOpen = SWARMVTAB_MAX_OPEN;
if( bSwarm ){
rc = unionOpenDatabase(pTab, 0, pzErr);
}else{
+2 -2
View File
@@ -2021,7 +2021,7 @@ static int ChooseLeaf(
){
int rc;
int ii;
RtreeNode *pNode;
RtreeNode *pNode = 0;
rc = nodeAcquire(pRtree, 1, 0, &pNode);
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
@@ -2896,7 +2896,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
*/
if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){
int rc2;
RtreeNode *pChild;
RtreeNode *pChild = 0;
i64 iChild = nodeGetRowid(pRtree, pRoot, 0);
rc = nodeAcquire(pRtree, iChild, pRoot, &pChild);
if( rc==SQLITE_OK ){
+29
View File
@@ -263,6 +263,24 @@ FTS5_SRC = \
$(TOP)/ext/fts5/fts5_varint.c \
$(TOP)/ext/fts5/fts5_vocab.c \
LSM1_SRC = \
$(TOP)/ext/lsm1/lsm.h \
$(TOP)/ext/lsm1/lsmInt.h \
$(TOP)/ext/lsm1/lsm_ckpt.c \
$(TOP)/ext/lsm1/lsm_file.c \
$(TOP)/ext/lsm1/lsm_log.c \
$(TOP)/ext/lsm1/lsm_main.c \
$(TOP)/ext/lsm1/lsm_mem.c \
$(TOP)/ext/lsm1/lsm_mutex.c \
$(TOP)/ext/lsm1/lsm_shared.c \
$(TOP)/ext/lsm1/lsm_sorted.c \
$(TOP)/ext/lsm1/lsm_str.c \
$(TOP)/ext/lsm1/lsm_tree.c \
$(TOP)/ext/lsm1/lsm_unix.c \
$(TOP)/ext/lsm1/lsm_varint.c \
$(TOP)/ext/lsm1/lsm_vtab.c \
$(TOP)/ext/lsm1/lsm_win32.c
# Generated source code files
#
@@ -279,6 +297,8 @@ SRC += \
# Source code to the test files.
#
TESTSRC = \
$(TOP)/ext/expert/sqlite3expert.c \
$(TOP)/ext/expert/test_expert.c \
$(TOP)/ext/fts3/fts3_term.c \
$(TOP)/ext/fts3/fts3_test.c \
$(TOP)/ext/rbu/test_rbu.c \
@@ -766,6 +786,10 @@ fts5.c: $(FTS5_SRC) $(FTS5_HDR)
tclsh $(TOP)/ext/fts5/tool/mkfts5c.tcl
cp $(TOP)/ext/fts5/fts5.h .
lsm1.c: $(LSM1_SRC)
tclsh $(TOP)/ext/lsm1/tool/mklsm1c.tcl
cp $(TOP)/ext/lsm1/lsm.h .
userauth.o: $(TOP)/ext/userauth/userauth.c $(HDR) $(EXTHDR)
$(TCCX) -DSQLITE_CORE -c $(TOP)/ext/userauth/userauth.c
@@ -787,6 +811,9 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $
sqlite3_analyzer$(EXE): sqlite3_analyzer.c
$(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB)
sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c
$(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB)
CHECKER_DEPS =\
$(TOP)/tool/mkccode.tcl \
sqlite3.c \
@@ -1013,9 +1040,11 @@ clean:
rm -f sqlite3rc.h
rm -f shell.c sqlite3ext.h
rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c
rm -f sqlite3_expert sqlite3_expert.exe
rm -f sqlite-*-output.vsix
rm -f mptester mptester.exe
rm -f fuzzershell fuzzershell.exe
rm -f fuzzcheck fuzzcheck.exe
rm -f sqldiff sqldiff.exe
rm -f fts5.* fts5parse.*
rm -f lsm.h lsm1.c
+63 -54
View File
@@ -1,9 +1,9 @@
C Use\sa\ssymbolic\sconstant\sinstead\sof\sa\sliteral\s(-1)\sto\sidentify\sa\nwarn-on-contention\smutex.
D 2017-11-28T07:47:57.520
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
C Merge\slatest\strunk\schanges\sinto\sthis\sbranch.
D 2017-12-16T19:16:24.821
F Makefile.in ceb40bfcb30ebba8e1202b34c56ff7e13e112f9809e2381d99be32c2726058f5
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44
F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
F Makefile.msc 6480671f7c129e61208d69492b3c71ce4310d49fceac83cfb17f1c081e242b69
F README.md eeae1e552f93ef72ef7c5b8f6647b368a001c28820ad1df179d3dae602bef681
F VERSION 0c10cdfed866fdd2d80434f64f042c3330f1daaed12e54287beb104f04b3faaf
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -40,6 +40,12 @@ F ext/README.md fd5f78013b0a2bc6f0067afb19e6ad040e89a10179b4f6f03eee58fac5f169bd
F ext/async/README.txt e12275968f6fde133a80e04387d0e839b0c51f91
F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c 4791c5e064aea81b2b829fa95228b22283380ee370ea88a1e580103b75516ebf
F ext/expert/expert1.test 1033e43071b69dc2f4e88fbf03fc7f18846c9865cac14f28c80f581437f09acb
F ext/expert/sqlite3expert.c 6ed4e84a06d1a29b2cf3009c0266573b88602d098055caa46c467154a64e0959
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
F ext/expert/test_expert.c 85f5c743a899063fa48296d21de2f32c26d09a21c8582b2a0bc482e8de183e7a
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea
@@ -105,7 +111,7 @@ F ext/fts5/fts5_buffer.c 1dd1ec0446b3acfc2d7d407eb894762a461613e2695273f48e449bf
F ext/fts5/fts5_config.c 5af9c360e99669d29f06492c370892394aba0857
F ext/fts5/fts5_expr.c 01048018d21524e2c302b063ff5c3cdcf546e03297215e577205d85b47499deb
F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301546dd55
F ext/fts5/fts5_index.c 2ce9d50ec5508b8205615aad69e1c9b2c77f017f21d4479e1fb2079c01fdd017
F ext/fts5/fts5_index.c 5fe14375a29e8a7aa8f3e863babe180a19269206c254c8f47b216821d4ac1e15
F ext/fts5/fts5_main.c 24868f88ab2a865defbba7a92eebeb726cc991eb092b71b5f5508f180c72605b
F ext/fts5/fts5_storage.c fb5ef3c27073f67ade2e1bea08405f9e43f68f5f3676ed0ab7013bce5ba10be6
F ext/fts5/fts5_tcl.c a7df39442ae674dde877cf06fe02ebb7658e69c179a4d223241c90df4f14b54e
@@ -183,7 +189,7 @@ F ext/fts5/test/fts5plan.test e30e8378441114ef6977a3dc24ecd203caa670d782124dfc9a
F ext/fts5/test/fts5porter.test 8d08010c28527db66bc3feebd2b8767504aaeb9b101a986342fa7833d49d0d15
F ext/fts5/test/fts5porter2.test 0d251a673f02fa13ca7f011654873b3add20745f7402f108600a23e52d8c7457
F ext/fts5/test/fts5prefix.test a0fa67b06650f2deaa7bf27745899d94e0fb547ad9ecbd08bfad98c04912c056
F ext/fts5/test/fts5query.test bdb6fd9e73268cfc07f789f1448cd71ea78acb02e481c619f286289ea18ca518
F ext/fts5/test/fts5query.test ac363b17a442620bb0780e93c24f16a5f963dfe2f23dc85647b869efcfada728
F ext/fts5/test/fts5rank.test 6e149da77a269923a8439aaa52366e49b85be4721902662da39a5ded16ed85d9
F ext/fts5/test/fts5rebuild.test 6d09fd54b1170a1e54fe17b808bbf17fba3154956cc2f065dd94bf1e3d254f63
F ext/fts5/test/fts5restart.test 835ecc8f449e3919f72509ab58056d0cedca40d1fe04108ccf8ac4c2ba41f415
@@ -210,7 +216,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c 635775226d07c743c770888a9dd5175afc6e67d3e28a4032b7fedc3bcaa92e65
F ext/icu/icu.c c2c7592574c08cd1270d909b8fb8797f6ea1f49e931e71dbcc25506b9b224580
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa5104813bad
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
@@ -239,15 +245,15 @@ F ext/lsm1/lsm-test/lsmtest_tdb4.c 47e8bb5eba266472d690fb8264f1855ebdba0ae5a0e54
F ext/lsm1/lsm-test/lsmtest_util.c 241622db5a332a09c8e6e7606b617d288a37b557f7d3bce0bb97809f67cc2806
F ext/lsm1/lsm-test/lsmtest_win32.c 0e0a224674c4d3170631c41b026b56c7e1672b151f5261e1b4cc19068641da2d
F ext/lsm1/lsm.h 0f6f64ff071471cb87bf98beb8386566f30ea001
F ext/lsm1/lsmInt.h e9e5c5f08e35a104086102b3def94ee69cbc0d39002f6596f5c80a640439628e
F ext/lsm1/lsm_ckpt.c ac6fb4581983291c2e0be6fbb68f12b26f0c08d606835c05417be1323d0fdd03
F ext/lsm1/lsm_file.c 4b3fb56336fbc9d941e1b2042e809d986feebdc41e73dc7fc4fdc0dd1bd4274d
F ext/lsm1/lsmInt.h 5983690e05e83653cc01ba9d8fbf8455e534ddf8349ed9adedbf46a7549760b0
F ext/lsm1/lsm_ckpt.c 0eabfaf812ddb4ea43add38f05e430694cd054eb622c3e35af4c43118a2d5321
F ext/lsm1/lsm_file.c 3c51841d5b3e7da162693cbac9a9f47eeedf6bcbbe2969a4d25e30c428c9fe36
F ext/lsm1/lsm_log.c a8bf334532109bba05b09a504ee45fc393828b0d034ca61ab45e3940709d9a7c
F ext/lsm1/lsm_main.c 15e73ccdafdd44ddeefc29e332079d88ba8f00c12c797b3c2b63d3171b5afce8
F ext/lsm1/lsm_main.c 801295038b548ae2e5fae93f08c3f945154f40848a03ff26b16eab5d04ba573a
F ext/lsm1/lsm_mem.c 4c51ea9fa285ee6e35301b33491642d071740a0a
F ext/lsm1/lsm_mutex.c 378edf0a2b142b4f7640ee982df06d50b98788ea
F ext/lsm1/lsm_shared.c 76adfc1ed9ffebaf92746dde4b370ccc48143ca8b05b563816eadd2aadf1c525
F ext/lsm1/lsm_sorted.c 8f899fb64a4c736ff3c27d5126c7ce181129ddffde947fe5fb657a7a413f470b
F ext/lsm1/lsm_sorted.c d07ff7c28758542b8b4da4b5a1fb67b22a4d33e50e7f684cffe1f6c45cf5182c
F ext/lsm1/lsm_str.c 65e361b488c87b10bf3e5c0070b14ffc602cf84f094880bece77bbf6678bca82
F ext/lsm1/lsm_tree.c 682679d7ef2b8b6f2fe77aeb532c8d29695bca671c220b0abac77069de5fb9fb
F ext/lsm1/lsm_unix.c 57361bcf5b1a1a028f5d66571ee490e9064d2cfb145a2cc9e5ddade467bb551b
@@ -256,6 +262,7 @@ F ext/lsm1/lsm_vtab.c 529255dc704289001b225d97e57e0cfa14b29c3f281c7349cfa8fdb655
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
F ext/lsm1/test/lsm1_common.tcl 5ed4bab07c93be2e4f300ebe46007ecf4b3e20bc5fbe1dedaf04a8774a6d8d82
F ext/lsm1/test/lsm1_simple.test ca949efefa102f4644231dcd9291d8cda7699a4ce1006b26e0e3fcb72233f422
F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f6078e07335398b0
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
@@ -277,7 +284,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
F ext/misc/rot13.c 540a169cb0d74f15522a8930b0cccdcb37a4fd071d219a5a083a319fc6e8db77
F ext/misc/scrub.c 1c5bfb8b0cd18b602fcb55755e84abf0023ac2fb
F ext/misc/series.c f3c0dba5c5c749ce1782b53076108f87cf0b71041eb6023f727a9c50681da564
F ext/misc/sha1.c 0b9e9b855354910d3ca467bf39099d570e73db56
@@ -286,7 +293,7 @@ F ext/misc/showauth.c 732578f0fe4ce42d577e1c86dc89dd14a006ab52
F ext/misc/spellfix.c 41cf26c6b89fcaa8798ae10ae64d39c1f1d9d6995152e545bd491c13058b8fac
F ext/misc/stmt.c 6f16443abb3551e3f5813bb13ba19a30e7032830015b0f92fe0c0453045c0a11
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
F ext/misc/unionvtab.c 1e0ebc5078e1a916db191bcd88f87e94ea7ba4aa563ee30ff706261cb4b39461
F ext/misc/unionvtab.c de36c2c45583d68f99e45b392311967066b02e2651d05697da783698b245b387
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
F ext/misc/vfsstat.c bf10ef0bc51e1ad6756629e1edb142f7a8db1178
F ext/misc/vtablog.c 31d0d8f4406795679dcd3a67917c213d3a2a5fb3ea5de35f6e773491ed7e13c9
@@ -337,7 +344,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c cc91b6905bf55512c6ebc7dfdd37ac81c86f1753db8cfa6d62f0ee864464044f
F ext/rtree/rtree.c 2111f685ae07988622c241f819b56fea60782f56e32f97e334473c59f6083481
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 82a353747fcab1083d114b2ac84723dfefdbf86c1a6e1df57bf588c7d4285436
F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
@@ -394,7 +401,7 @@ F ext/userauth/userauth.c 3410be31283abba70255d71fd24734e017a4497f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk fbe15be384ec172be0cc30efc91cda61ca16bd5d833e8b812cf653ccb0c74977
F main.mk 6ef9e2b1c3f1e46c9e3c2b362531cbc277f7bea1a66fe610a3a7c4173b091ba4
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -416,14 +423,14 @@ F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
F src/btree.c b83a6b03f160528020bb965f0c3a40af5286cd4923c3870fd218177f03a120a7
F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
F src/build.c 514db9d494ed29155e552f2ec2fa7c55c0241f847c683156b7c017f4b0bad9fa
F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
F src/build.c 87b68e3b45559ec404b12f095f0ba5f06f91a6dd2d21bd8443e41d8ac2e67196
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
F src/delete.c e6a70fb58f6628f0ffc6d7221a6702c0d7b342c82520385b3996b364c22e0cb3
F src/delete.c 74667ad914ac143731a444a1bacf29ceb18f6eded8a0dd17aafae80baa07f8bb
F src/expr.c fe11b91bb65b869143bd42023427c4429778ae42c0a0db7762f68f75b347a958
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
@@ -436,7 +443,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
F src/main.c 6a0cc1c7b8ab92374effecdd7b92792b3273a255c70575b7d67bd9a4315e6d3a
F src/main.c 903c4e3eb189d4ce94748dc7f442f9136177cb2eedb27185f83a525edb0c4530
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -445,7 +452,7 @@ F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
F src/memjournal.c 6f3d36a0a8f72f48f6c3c722f04301ac64f2515435fa42924293e46fc7994661
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
F src/mutex.c 20172f2cc43c4542f7860ab6bafdd16965822c4e56650d62628059a48c7f43c4
F src/mutex.c b021263554c8a3995e9d53193b8194b96d1ed28e06c3b532dd7f7d29cf0c7d53
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
F src/mutex_unix.c 27bb6cc49485ee46711a6580ab7b3f1402211d23
@@ -455,8 +462,8 @@ F src/os.c 22d31db3ca5a96a408fbf1ceeaaebcaf64c87024d2ff9fe1cf2ddbec3e75c104
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c e87cef0bb894b94d96ee3af210be669549d111c580817d14818101b992640767
F src/os_win.c 7f36120492e4a23c48d1dd685edf29ae459c6d555660c61f1323cea3e5a1191d
F src/os_unix.c 7fc2735390a7809d5d893ed735d994ff12521224b89738226fff6f1a0aa1c932
F src/os_win.c 0a4afa35cc8e812000df3ea2f64b476131b39e29e75d8007d0504726e4761de4
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
@@ -464,19 +471,19 @@ F src/parse.y d79001da275bfe344b409006b85e81e486a0f6afc3762fdf0944f000f4aa0111
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
F src/pragma.c d04725ac25387d9638919e197fb009f378e13af7bf899516979e54b3164e3602
F src/pragma.c bea56df3ae0637768c0da4fbbb8f2492f780980d95000034a105ff291bf7ca69
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
F src/prepare.c 7cf451f903ad92a14e22de415a13e7a7d30f1bd23b3d21eeb0dc7264723244c5
F src/prepare.c 259f4e7960c47082c9653f3d5f0c294abd68bb9c3aab86de7630700cba1c20fb
F src/printf.c 9506b4b96e59c0467047155f09015750cb2878aeda3d39e5610c1192ddc3c41c
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 17e220191860a64a18c084141e1a8b7309e166a6f2d42c02021af27ea080d157
F src/shell.c.in cb1b5e41ef9c081b2b8927ae32c9c384a9ec110ada808ebfe083ba7c8a19bbb8
F src/sqlite.h.in 8fd97993d48b50b9bade38c52f12d175942c9497c960905610c7b03a3e4b5818
F src/shell.c.in 6ffed0c589f5aff180789a8c8abf5b2d3e2eea7470c86b30e797887cb0c9d0e5
F src/sqlite.h.in 95afbec6e623843d702e727765efc833586fecc688867f41f87be7db3ff1fa62
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34
F src/sqliteInt.h 4c910d9c0d88a90e8639a4f83ef05f701ccfe731cf593e757444074f01df4964
F src/sqliteInt.h 4d6580ab911e9bc36447ef05bf4d2aab929dde161ac117c7de6220eef06d6175
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -496,7 +503,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c 3000f00b9b47b149d842059904c3fcab5f3871fb6aee7d7cc5756f0c64779ae3
F src/test_config.c 3904a8682aac58b77d20ca236face2b11e50781be4116004ba1ba79f69896ec9
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
@@ -524,7 +531,7 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c 74fcfb7f3b0ff1f871e62263dd84ffba46a8e9d477439115e0fb2035e4bf69e1
F src/test_tclsh.c 58052fe48efe8f579834f4648d239569f2efc6285f5019ebdf0040f58d16238d
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
@@ -535,7 +542,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
F src/treeview.c 08a83195de8fad3f00542e3c8b3c1eb1222c999817c9e301ffb7f332882b96dd
F src/trigger.c fc6be2a6e103d9e38b161e07d7db0ffb1f2218bd2f27ccdc0a3d1cc89e9cea0f
F src/trigger.c 775053eecf6b73062e243404b56f5064446254d5cce17d8704d5cdffd72a546a
F src/update.c 961bd1265d4d1e5cd65c9a54fa5122fb7aefcb003fcf2de0c092fceb7e58972c
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d01fa6f45bfad3b65fb2490513aa2e0676412c61b4b094340b513cf72c3704a4
@@ -544,19 +551,19 @@ F src/vdbe.c 3393b508d9ad084ffce232a7c53e375ef5ac99b50b685c5131fcdfce97a9d534
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
F src/vdbeaux.c b02a1f842c0e916285643b8475b7189f10b76f9e7edb5e2353a913c7980f90b5
F src/vdbeaux.c cf474d29372a30d0db84b0a9a74ab07117c9b831e1585a0fa335e2b445f4a95f
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 2ef9e66b301a1e575e32966c4c0fd4844e8eea37a2f02bae78c4f68f50a6ab30
F src/vdbemem.c 8478f7fb1948bf8fdeec7c2cb59ea58155c31258b9cd43c56d485e03ed40bd07
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c
F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c beeb71e4eab65dbf0d95f2717efc6ca3c0f5b3090ce67f3de63828f39a6ff053
F src/wal.c 5a3f464edd64596f601683ed321d12e6fd93c5fb9afdfb3653d6ffd0fee9c48f
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
F src/where.c 9752b68e03e2044f0faa4708fabb0189769067b660bffa931e1fd65736269659
F src/where.c 1617e7e42daf0ace7799204e3e9b7c9e75069aa2a0c8ddd24d1b9569b2a0b7e4
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
F src/wherecode.c 611fcabd05592ed2febd7d182f9621425b0466c5232d70e0981c842d429356d5
F src/wherecode.c ff2f079097a3bdce6ebabfde1419fba448c9ce5feb7cb964e8bfa2a4e27274ef
F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
@@ -787,7 +794,7 @@ F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
F test/fkey5.test 24dd28eb3d9f1b5a174f47e9899ace5facb08373a4223593c8c631e6cf9f7d5a
F test/fkey6.test d078a1e323a740062bed38df32b8a736fd320dc0
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
F test/fkey7.test 24076d43d3449f12f25503909ca4bfb5fc5fefd5af1f930723a496343eb28454
F test/fkey8.test e5372e32cdb4481f121ec3550703eeb7b4e0762c
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
F test/fordelete.test eb93a2f34137bb87bdab88fcab06c0bd92719aff
@@ -932,7 +939,7 @@ F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 73956798bace8982909c00476b216714a6d0559a
F test/icu.test 7fb00edc09e05d51e36be12b33e0af04e3394e3b02dbdcb2eefcb901203e28c4
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test 2fa2dfba1afe30eb830f327e7131dfadaa7a701d677de0eb65f9303d99e18fe0
@@ -1007,7 +1014,7 @@ F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
F test/like3.test 3608a2042b6f922f900fbfd5d3ce4e7eca57f7c4
F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e
F test/limit2.test e35f57bd3a62d7c5dcb5ac4306e675c75f974809
F test/limit2.test 360982809e03211636d2b18ddbc97d5da06826941370607e4b00e113f827cb5a
F test/loadext.test d077450695ddb5c1ea3ad7d48e5f5850fe732ad9
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
F test/lock.test be4fe08118fb988fed741f429b7dd5d65e1c90db
@@ -1063,7 +1070,7 @@ F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
F test/misc8.test ba03aaa08f02d62fbb8d3b2f5595c1b33aa9bbc5
F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7
F test/mjournal.test 946d7161cabbc45ecc818d7fa38c1925bbf36e5534a08a81fa0203ee7ced7d54
F test/mjournal.test 9d86e697dcbc5da2c4e8caba9b176b5765fe65e80c88c278b8c09a917e436795
F test/mmap1.test d2cfc1635171c434dcff0ece2f1c8e0a658807ce
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
F test/mmap3.test b3c297e78e6a8520aafcc1a8f140535594c9086e
@@ -1114,7 +1121,7 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 490e3333b9b1aefb7ebc6e9ab2ae0e382b7dd8713ccc4a2786b0f75467c2ab6b
F test/permutations.test 8ada8c1dee071e0fc275bc8bc2db7de537d625cad949d2200664b99a0a89eac5
F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
@@ -1173,7 +1180,7 @@ F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
F test/schema4.test 3b26c9fa916abb6dadf894137adcf41b7796f7b9
F test/schema5.test 29699b4421f183c8f0e88bd28ce7d75d13ea653e
F test/schema6.test e4bd1f23d368695eb9e7b51ef6e02ca0642ea2ab4a52579959826b5e7dce1f9b
F test/securedel.test 5f997cb6bd38727b81e0985f53ec386c99db6441b2b9e6357240649d29017239
F test/securedel.test 2f70b2449186a1921bd01ec9da407fbfa98c3a7a5521854c300c194b2ff09384
F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5
F test/select1.test 460a5824df01575b18f7fa4bd8e40d09de20c542e90c1543e164bc7d3b0a0bb7
F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56
@@ -1210,7 +1217,7 @@ F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test 9b95ba643eaa228376f06a898fb410ee9b6e57c1
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
F test/shell5.test 23939a4c51f0421330ea61dbd3c74f9c215f5f8d3d1a94846da6ffc777a35458
F test/shell6.test ab1592ebe881371f651f18ee6a0df21cbfb5310f88cb832ab642d4038f679772
F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3
F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f
F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
@@ -1223,6 +1230,7 @@ F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
F test/snapshot.test 85735bd997a4f6d710140c28fd860519a299649f
F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096
F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
@@ -1258,8 +1266,9 @@ F test/subselect.test 0966aa8e720224dbd6a5e769a3ec2a723e332303
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
F test/swarmvtab.test c2279311b44de032f86a8295a9b06818d864856f9428b4c99eee91a0d419cf25
F test/swarmvtab2.test 9a3a68a1e58d00f4ed6c68d12d52f2df971b9e22a80a41f6f8c1409abba8e5b4
F test/swarmvtab.test 9a3fd5ab3e9b3c976ad1b3d7646aab725114f2ac26b59395d0778b33bab6cdaf
F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c
F test/swarmvtab3.test c4c8d09e56ae99b90187ac225458f13f373873ea296fc442c7ad7511f25e7314
F test/swarmvtabfault.test 00aec54665909490f5c383f3cae3b5d18bd97c12490b429ff8752a3027acfa42
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
@@ -1456,7 +1465,7 @@ F test/triggerC.test 302d8995f5ffe63bbc15053abb3ef7a39cf5a092
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
F test/triggerE.test 15fa63f1097db1f83dd62d121616006978063d1f
F test/triggerF.test 6a8c22bd058cf467f0c7d112afe87f7a8c579c0c4681b914b8f19020f48528a4
F test/triggerG.test 175cafdc6399d85231a09e82e051b0e45a2fd1f23dd08ae715bc359716149ab6
F test/triggerG.test d5caeef6144ede2426dd13211fd72248241ff2ebc68e12a4c0bf30f5faa21499
F test/tt3_checkpoint.c 9e75cf7c1c364f52e1c47fd0f14c4340a9db0fe1
F test/tt3_index.c 39eec10a35f57672225be4d182862152896dee4a
F test/tt3_lookaside1.c 0377e202c3c2a50d688cb65ba203afeda6fafeb9
@@ -1532,9 +1541,9 @@ F test/walmode.test 4022fe03ae6e830583672caa101f046438a0473c
F test/walnoshm.test 84ca10c544632a756467336b7c3b864d493ee496
F test/waloverwrite.test dad2f26567f1b45174e54fbf9a8dc1cb876a7f03
F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6
F test/walprotocol.test 0b92feb132ccebd855494d917d3f6c2d717ace20
F test/walprotocol.test a112aba0b79e3adeaa485fed09484b32c654e97df58e454aa8489ac2cd57bf84
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
F test/walro2.test 8812e514c968bf4ee317571fafedac43443360ae23edd7d0f4ef1eae0c13e8e8
F test/walro2.test 5cd57d192ee334c3894330303b5f8cb6789fef49b2c83ad1b50b9b132d0f7ae1
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
@@ -1600,7 +1609,7 @@ F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
F tool/lemon.c e6056373044d55296d21f81467dba7632bbb81dc49af072b3f0e76338771497e
F tool/lempar.c 105d0d9cbe5a25d24d4769241ffbfc63ac7c09e6ccee0dc43dcc8a4c4ae4e426
F tool/lempar.c 967ebf585cd09b11b89d255d213865109a9c4ff075680d22580a2826de288c89
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c 11346aa019e2e77a00902aa7d0cabd27bd2e8cca
@@ -1678,7 +1687,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 7d0b12fcb58353b883ffce77df824a5cc8b1e913a21ec3f22fb73481a398c916
R a940a7b7e2663c64f019728def2f503f
P 373fa21bffd37053bb1a741d3ace2f003a5639bf373c20ea7bb24a31080888b3 64487d658cb3b6c8c67f1e198c70813c963de52599f3ea974bdc2aa432e74de9
R 864c298149f75794a8b0c88eee2c8573
U dan
Z d7c77380d4461a6101913d9af19a0151
Z b67f6466a953a4099311404f5788e02e
+1 -1
View File
@@ -1 +1 @@
12a23c0a66fac5c9674120b390f6abaeaba3f7ff04693b281af1eefb93d6f47c
d5b597b52a1213cdf382d96f4df3535727be0852b25bafd12bbef54da946c5f2
+12
View File
@@ -4364,6 +4364,18 @@ KeyInfo *sqlite3KeyInfoOfIndex(Parse *pParse, Index *pIdx){
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
if( pParse->nErr ){
assert( pParse->rc==SQLITE_ERROR_MISSING_COLLSEQ );
if( pIdx->bNoQuery==0 ){
/* Deactivate the index because it contains an unknown collating
** sequence. The only way to reactive the index is to reload the
** schema. Adding the missing collating sequence later does not
** reactive the index. The application had the chance to register
** the missing index using the collation-needed callback. For
** simplicity, SQLite will not give the application a second chance.
*/
pIdx->bNoQuery = 1;
pParse->rc = SQLITE_ERROR_RETRY;
}
sqlite3KeyInfoUnref(pKey);
pKey = 0;
}
+1
View File
@@ -105,6 +105,7 @@ CollSeq *sqlite3GetCollSeq(
assert( !p || p->xCmp );
if( p==0 ){
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
}
return p;
}
+1 -1
View File
@@ -39,7 +39,7 @@
**
** Jean Meeus
** Astronomical Algorithms, 2nd Edition, 1998
** ISBM 0-943396-61-1
** ISBN 0-943396-61-1
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
+1 -1
View File
@@ -283,11 +283,11 @@ void sqlite3DeleteFrom(
#ifndef SQLITE_OMIT_TRIGGER
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
isView = pTab->pSelect!=0;
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#else
# define pTrigger 0
# define isView 0
#endif
bComplex = pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0);
#ifdef SQLITE_OMIT_VIEW
# undef isView
# define isView 0
+17 -2
View File
@@ -22,7 +22,7 @@
#ifdef SQLITE_ENABLE_RTREE
# include "rtree.h"
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
# include "sqliteicu.h"
#endif
#ifdef SQLITE_ENABLE_JSON1
@@ -806,6 +806,21 @@ int sqlite3_db_config(sqlite3 *db, int op, ...){
rc = setupLookaside(db, pBuf, sz, cnt);
break;
}
case SQLITE_DBCONFIG_FULL_EQP: {
int onoff = va_arg(ap, int);
int *pRes = va_arg(ap, int*);
if( onoff>0 ){
db->bFullEQP = 1;
}else if( onoff==0 ){
db->bFullEQP = 0;
}
sqlite3ExpirePreparedStatements(db);
if( pRes ){
*pRes = db->bFullEQP;
}
rc = SQLITE_OK;
break;
}
default: {
static const struct {
int op; /* The opcode */
@@ -3050,7 +3065,7 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
}
+1 -1
View File
@@ -134,7 +134,7 @@ static void checkMutexFree(sqlite3_mutex *p){
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
#if SQLITE_ENABLE_API_ARMOR
if( p->iType<2 ){
if( ((CheckMutex*)p)->iType<2 )
#endif
{
CheckMutex *pCheck = (CheckMutex*)p;
+8 -5
View File
@@ -483,7 +483,7 @@ static struct unix_syscall {
#else
{ "munmap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMunmap ((void*(*)(void*,size_t))aSyscall[23].pCurrent)
#define osMunmap ((int(*)(void*,size_t))aSyscall[23].pCurrent)
#if HAVE_MREMAP && (!defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0)
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
@@ -4165,7 +4165,7 @@ static int unixShmSystemLock(
/* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
assert( sqlite3_mutex_held(pShmNode->mutex) || pShmNode->nRef==0 );
assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) );
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
@@ -5799,7 +5799,7 @@ static int unixOpen(
** a file-descriptor on the directory too. The first time unixSync()
** is called the directory file descriptor will be fsync()ed and close()d.
*/
int syncDir = (isCreate && (
int isNewJrnl = (isCreate && (
eType==SQLITE_OPEN_MASTER_JOURNAL
|| eType==SQLITE_OPEN_MAIN_JOURNAL
|| eType==SQLITE_OPEN_WAL
@@ -5869,7 +5869,7 @@ static int unixOpen(
}else if( !zName ){
/* If zName is NULL, the upper layer is requesting a temp file. */
assert(isDelete && !syncDir);
assert(isDelete && !isNewJrnl);
rc = unixGetTempname(pVfs->mxPathname, zTmpname);
if( rc!=SQLITE_OK ){
return rc;
@@ -5915,6 +5915,9 @@ static int unixOpen(
}
if( fd<0 ){
rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zName);
/* If unable to create a journal, change the error code to
** indicate that the directory permissions are wrong. */
if( isNewJrnl && osAccess(zName, F_OK) ) rc = SQLITE_READONLY_DIRECTORY;
goto open_finished;
}
@@ -5974,7 +5977,7 @@ static int unixOpen(
if( isReadonly ) ctrlFlags |= UNIXFILE_RDONLY;
noLock = eType!=SQLITE_OPEN_MAIN_DB;
if( noLock ) ctrlFlags |= UNIXFILE_NOLOCK;
if( syncDir ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( isNewJrnl ) ctrlFlags |= UNIXFILE_DIRSYNC;
if( flags & SQLITE_OPEN_URI ) ctrlFlags |= UNIXFILE_URI;
#if SQLITE_ENABLE_LOCKING_STYLE
+1 -1
View File
@@ -3742,7 +3742,7 @@ static int winShmSystemLock(
int rc = 0; /* Result code form Lock/UnlockFileEx() */
/* Access to the winShmNode object is serialized by the caller */
assert( sqlite3_mutex_held(pFile->mutex) || pFile->nRef==0 );
assert( pFile->nRef==0 || sqlite3_mutex_held(pFile->mutex) );
OSTRACE(("SHM-LOCK file=%p, lock=%d, offset=%d, size=%d\n",
pFile->hFile.h, lockType, ofst, nByte));
+1
View File
@@ -1080,6 +1080,7 @@ void sqlite3Pragma(
** type: Column declaration type.
** notnull: True if 'NOT NULL' is part of column declaration
** dflt_value: The default value for the column, if any.
** pk: Non-zero for PK fields.
*/
case PragTyp_TABLE_INFO: if( zRight ){
Table *pTab;
+10 -8
View File
@@ -655,8 +655,6 @@ static int sqlite3Prepare(
end_prepare:
sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
}
static int sqlite3LockAndPrepare(
@@ -669,6 +667,7 @@ static int sqlite3LockAndPrepare(
const char **pzTail /* OUT: End of parsed string */
){
int rc;
int cnt = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
@@ -679,15 +678,18 @@ static int sqlite3LockAndPrepare(
}
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
if( rc==SQLITE_SCHEMA ){
sqlite3ResetOneSchema(db, -1);
sqlite3_finalize(*ppStmt);
do{
/* Make multiple attempts to compile the SQL, until it either succeeds
** or encounters a permanent error. A schema problem after one schema
** reset is considered a permanent error. */
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
}
assert( rc==SQLITE_OK || *ppStmt==0 );
}while( rc==SQLITE_ERROR_RETRY
|| (rc==SQLITE_SCHEMA && (sqlite3ResetOneSchema(db,-1), cnt++)==0) );
sqlite3BtreeLeaveAll(db);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
sqlite3_mutex_leave(db->mutex);
assert( rc==SQLITE_OK || *ppStmt==0 );
return rc;
}
+7 -10
View File
@@ -1190,12 +1190,9 @@ static void output_csv(ShellState *p, const char *z, int bSep){
}
}
if( i==0 ){
putc('"', out);
for(i=0; z[i]; i++){
if( z[i]=='"' ) putc('"', out);
putc(z[i], out);
}
putc('"', out);
char *zQuoted = sqlite3_mprintf("\"%w\"", z);
utf8_printf(out, "%s", zQuoted);
sqlite3_free(zQuoted);
}else{
utf8_printf(out, "%s", z);
}
@@ -3898,10 +3895,10 @@ static int lintFkeyIndexes(
**
** 0. The text of an SQL statement similar to:
**
** "EXPLAIN QUERY PLAN SELECT rowid FROM child_table WHERE child_key=?"
** "EXPLAIN QUERY PLAN SELECT 1 FROM child_table WHERE child_key=?"
**
** This is the same SELECT that the foreign keys implementation needs
** to run internally on child tables. If there is an index that can
** This SELECT is similar to the one that the foreign keys implementation
** needs to run internally on child tables. If there is an index that can
** be used to optimize this query, then it can also be used by the FK
** implementation to optimize DELETE or UPDATE statements on the parent
** table.
@@ -3929,7 +3926,7 @@ static int lintFkeyIndexes(
*/
const char *zSql =
"SELECT "
" 'EXPLAIN QUERY PLAN SELECT rowid FROM ' || quote(s.name) || ' WHERE '"
" 'EXPLAIN QUERY PLAN SELECT 1 FROM ' || quote(s.name) || ' WHERE '"
" || group_concat(quote(s.name) || '.' || quote(f.[from]) || '=?' "
" || fkey_collate_clause("
" f.[table], COALESCE(f.[to], p.[name]), s.name, f.[from]),' AND ')"
+30 -3
View File
@@ -470,6 +470,8 @@ int sqlite3_exec(
** the most recent error can be obtained using
** [sqlite3_extended_errcode()].
*/
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
@@ -515,6 +517,7 @@ int sqlite3_exec(
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5<<8))
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@@ -2057,7 +2060,6 @@ struct sqlite3_mem_methods {
** into which is written 0 or 1 to indicate whether checkpoints-on-close
** have been disabled - 0 if they are not disabled, 1 if they are.
** </dd>
**
** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt>
** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates
** the [query planner stability guarantee] (QPSG). When the QPSG is active,
@@ -2068,7 +2070,16 @@ struct sqlite3_mem_methods {
** the QPSG active, SQLite will always use the same query plan in the field as
** was used during testing in the lab.
** </dd>
**
** <dt>SQLITE_DBCONFIG_FULL_EQP</dt>
** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not
** include output for any operations performed by trigger programs. This
** option is used to set or clear (the default) a flag that governs this
** behavior. The first parameter passed to this operation is an integer -
** non-zero to enable output for trigger programs, or zero to disable it.
** The second parameter is a pointer to an integer into which is written
** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if
** it is not disabled, 1 if it is.
** </dd>
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2079,7 +2090,7 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION 1005 /* int int* */
#define SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE 1006 /* int int* */
#define SQLITE_DBCONFIG_ENABLE_QPSG 1007 /* int int* */
#define SQLITE_DBCONFIG_FULL_EQP 1008 /* int int* */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -8284,6 +8295,22 @@ int sqlite3_vtab_config(sqlite3*, int op, ...);
*/
int sqlite3_vtab_on_conflict(sqlite3 *);
/*
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
**
** This function may only be called from within a call to the [xBestIndex]
** method of a [virtual table implementation].
**
** The first argument must be the database handle with which the virtual
** table is associated (the one passed to the [xConnect] or [xCreate] method
** to create the sqlite3_vtab object. The second argument must be an index
** into the aConstraint[] array belonging to the sqlite3_index_info structure
** passed to xBestIndex. This function returns a pointer to a buffer
** containing the name of the collation sequence for the corresponding
** constraint.
*/
SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3*, int);
/*
** CAPI3REF: Conflict resolution modes
** KEYWORDS: {conflict resolution mode}
+4 -1
View File
@@ -1356,6 +1356,7 @@ struct sqlite3 {
u8 mTrace; /* zero or more SQLITE_TRACE flags */
u8 skipBtreeMutex; /* True if no shared-cache backends */
u8 nSqlExec; /* Number of pending OP_SqlExec opcodes */
u8 bFullEQP; /* Include triggers in EQP output */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -1421,6 +1422,7 @@ struct sqlite3 {
VtabCtx *pVtabCtx; /* Context for active vtab connect/create */
VTable **aVTrans; /* Virtual tables with open transactions */
VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */
void *pBestIndexCtx; /* For sqlite3_vtab_collation() */
#endif
Hash aFunc; /* Hash table of connection functions */
Hash aCollSeq; /* All collating sequences */
@@ -2172,6 +2174,7 @@ struct Index {
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
int nSample; /* Number of elements in aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
@@ -2984,7 +2987,7 @@ struct Parse {
int nMem; /* Number of memory cells used so far */
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */
int iSelfTab; /* Table for associated with an index on expr, or negative
int iSelfTab; /* Table associated with an index on expr, or negative
** of the base register during check-constraint eval */
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
+12
View File
@@ -429,6 +429,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "icu", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_ICU_COLLATIONS
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_INCRBLOB
Tcl_SetVar2(interp, "sqlite_options", "incrblob", "0", TCL_GLOBAL_ONLY);
#else
@@ -696,6 +702,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY);
Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_FAST_SECURE_DELETE
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "fast_secure_delete", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_SECURE_DELETE
Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY);
#else
+3
View File
@@ -104,6 +104,8 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
#ifdef SQLITE_ENABLE_ZIPVFS
extern int Zipvfs_Init(Tcl_Interp*);
#endif
extern int TestExpert_Init(Tcl_Interp*);
Tcl_CmdInfo cmdInfo;
/* Since the primary use case for this binary is testing of SQLite,
@@ -166,6 +168,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp);
#endif
TestExpert_Init(interp);
Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
+1 -1
View File
@@ -875,7 +875,7 @@ static TriggerPrg *codeRowTrigger(
VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
transferParseError(pParse, pSubParse);
if( db->mallocFailed==0 ){
if( db->mallocFailed==0 && pParse->nErr==0 ){
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
}
pProgram->nMem = pSubParse->nMem;
+100 -88
View File
@@ -1639,6 +1639,8 @@ int sqlite3VdbeList(
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
int bFull = (p->explain==1 || db->bFullEQP);
Op *pOp = 0;
assert( p->explain );
assert( p->magic==VDBE_MAGIC_RUN );
@@ -1651,7 +1653,7 @@ int sqlite3VdbeList(
releaseMemArray(pMem, 8);
p->pResultSet = 0;
if( p->rc==SQLITE_NOMEM_BKPT ){
if( p->rc==SQLITE_NOMEM ){
/* This happens if a malloc() inside a call to sqlite3_column_text() or
** sqlite3_column_text16() failed. */
sqlite3OomFault(db);
@@ -1666,7 +1668,7 @@ int sqlite3VdbeList(
** encountered, but p->pc will eventually catch up to nRow.
*/
nRow = p->nOp;
if( p->explain==1 ){
if( bFull ){
/* The first 8 memory cells are used for the result set. So we will
** commandeer the 9th cell to use as storage for an array of pointers
** to trigger subprograms. The VDBE is guaranteed to have at least 9
@@ -1686,17 +1688,11 @@ int sqlite3VdbeList(
do{
i = p->pc++;
}while( i<nRow && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
if( i>=nRow ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
}else if( db->u1.isInterrupted ){
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else{
char *zP4;
Op *pOp;
if( i>=nRow ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
break;
}
if( i<p->nOp ){
/* The output line number is small enough that we are still in the
** main program. */
@@ -1711,94 +1707,110 @@ int sqlite3VdbeList(
}
pOp = &apSub[j]->aOp[i];
}
if( p->explain==1 ){
pMem->flags = MEM_Int;
pMem->u.i = i; /* Program counter */
pMem++;
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
assert( pMem->z!=0 );
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem++;
/* When an OP_Program opcode is encounter (the only opcode that has
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
** has not already been seen.
*/
if( pOp->p4type==P4_SUBPROGRAM ){
int nByte = (nSub+1)*sizeof(SubProgram*);
int j;
for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break;
}
if( j==nSub && SQLITE_OK==sqlite3VdbeMemGrow(pSub, nByte, nSub!=0) ){
apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob;
pSub->n = nSub*sizeof(SubProgram*);
/* When an OP_Program opcode is encounter (the only opcode that has
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
** has not already been seen.
*/
if( bFull && pOp->p4type==P4_SUBPROGRAM ){
int nByte = (nSub+1)*sizeof(SubProgram*);
int j;
for(j=0; j<nSub; j++){
if( apSub[j]==pOp->p4.pProgram ) break;
}
if( j==nSub ){
p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
if( p->rc!=SQLITE_OK ){
rc = SQLITE_ERROR;
break;
}
apSub = (SubProgram **)pSub->z;
apSub[nSub++] = pOp->p4.pProgram;
pSub->flags |= MEM_Blob;
pSub->n = nSub*sizeof(SubProgram*);
nRow += pOp->p4.pProgram->nOp;
}
}
}while( p->explain==2 && pOp->opcode!=OP_Explain );
pMem->flags = MEM_Int;
pMem->u.i = pOp->p1; /* P1 */
pMem++;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p2; /* P2 */
pMem++;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p3; /* P3 */
pMem++;
if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
if( zP4!=pMem->z ){
pMem->n = 0;
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
if( rc==SQLITE_OK ){
if( db->u1.isInterrupted ){
p->rc = SQLITE_INTERRUPT;
rc = SQLITE_ERROR;
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
}else{
assert( pMem->z!=0 );
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
}
pMem++;
if( p->explain==1 ){
if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
char *zP4;
if( p->explain==1 ){
pMem->flags = MEM_Int;
pMem->u.i = i; /* Program counter */
pMem++;
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
assert( pMem->z!=0 );
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
pMem++;
}
pMem->flags = MEM_Str|MEM_Term;
pMem->n = 2;
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
pMem->enc = SQLITE_UTF8;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p1; /* P1 */
pMem++;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
pMem->flags = MEM_Int;
pMem->u.i = pOp->p2; /* P2 */
pMem++;
pMem->flags = MEM_Int;
pMem->u.i = pOp->p3; /* P3 */
pMem++;
if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
pMem->enc = SQLITE_UTF8;
#else
pMem->flags = MEM_Null; /* Comment */
#endif
}
zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
if( zP4!=pMem->z ){
pMem->n = 0;
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
}else{
assert( pMem->z!=0 );
pMem->n = sqlite3Strlen30(pMem->z);
pMem->enc = SQLITE_UTF8;
}
pMem++;
p->nResColumn = 8 - 4*(p->explain-1);
p->pResultSet = &p->aMem[1];
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
if( p->explain==1 ){
if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
pMem->n = 2;
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
pMem->enc = SQLITE_UTF8;
pMem++;
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Str|MEM_Term;
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
pMem->enc = SQLITE_UTF8;
#else
pMem->flags = MEM_Null; /* Comment */
#endif
}
p->nResColumn = 8 - 4*(p->explain-1);
p->pResultSet = &p->aMem[1];
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
}
return rc;
}
+8 -1
View File
@@ -1321,7 +1321,11 @@ static int valueFromExpr(
assert( pExpr!=0 );
while( (op = pExpr->op)==TK_UPLUS || op==TK_SPAN ) pExpr = pExpr->pLeft;
#if defined(SQLITE_ENABLE_STAT3_OR_STAT4)
if( op==TK_REGISTER ) op = pExpr->op2;
#else
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif
/* Compressed expressions only appear when parsing the DEFAULT clause
** on a table column definition, and hence only when pCtx==0. This
@@ -1416,7 +1420,10 @@ static int valueFromExpr(
return rc;
no_mem:
sqlite3OomFault(db);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
if( pCtx==0 || pCtx->pParse->nErr==0 )
#endif
sqlite3OomFault(db);
sqlite3DbFree(db, zVal);
assert( *ppVal==0 );
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
+1 -2
View File
@@ -2494,8 +2494,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
pInfo = walCkptInfo(pWal);
if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
|| 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
#endif
){
/* The WAL has been completely backfilled (or it is empty).
+39
View File
@@ -2879,6 +2879,7 @@ static int whereLoopAddBtree(
testcase( pNew->iTab!=pSrc->iCursor ); /* See ticket [98d973b8f5] */
continue; /* Partial index inappropriate for this query */
}
if( pProbe->bNoQuery ) continue;
rSize = pProbe->aiRowLogEst[0];
pNew->u.btree.nEq = 0;
pNew->u.btree.nBtm = 0;
@@ -3138,6 +3139,35 @@ static int whereLoopAddVirtualOne(
}
/*
** Context object used to pass information from whereLoopAddVirtual()
** to sqlite3_vtab_collation().
*/
struct BestIndexCtx {
WhereClause *pWC;
sqlite3_index_info *pIdxInfo;
Parse *pParse;
};
/*
** If this function is invoked from within an xBestIndex() callback, it
** returns a pointer to a buffer containing the name of the collation
** sequence associated with element iCons of the sqlite3_index_info.aConstraint
** array. Or, if iCons is out of range or there is no active xBestIndex
** call, return NULL.
*/
const char *sqlite3_vtab_collation(sqlite3 *db, int iCons){
struct BestIndexCtx *p = (struct BestIndexCtx*)db->pBestIndexCtx;
const char *zRet = 0;
if( p && iCons>=0 && iCons<p->pIdxInfo->nConstraint ){
int iTerm = p->pIdxInfo->aConstraint[iCons].iTermOffset;
Expr *pX = p->pWC->a[iTerm].pExpr;
CollSeq *pC = sqlite3BinaryCompareCollSeq(p->pParse,pX->pLeft,pX->pRight);
zRet = (pC ? pC->zName : "BINARY");
}
return zRet;
}
/*
** Add all WhereLoop objects for a table of the join identified by
** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table.
@@ -3179,6 +3209,8 @@ static int whereLoopAddVirtual(
WhereLoop *pNew;
Bitmask mBest; /* Tables used by best possible plan */
u16 mNoOmit;
struct BestIndexCtx bic;
void *pSaved;
assert( (mPrereq & mUnusable)==0 );
pWInfo = pBuilder->pWInfo;
@@ -3200,6 +3232,12 @@ static int whereLoopAddVirtual(
return SQLITE_NOMEM_BKPT;
}
bic.pWC = pWC;
bic.pIdxInfo = p;
bic.pParse = pParse;
pSaved = pParse->db->pBestIndexCtx;
pParse->db->pBestIndexCtx = (void*)&bic;
/* First call xBestIndex() with all constraints usable. */
WHERETRACE(0x40, (" VirtualOne: all usable\n"));
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
@@ -3276,6 +3314,7 @@ static int whereLoopAddVirtual(
if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr);
sqlite3DbFreeNN(pParse->db, p);
pParse->db->pBestIndexCtx = pSaved;
return rc;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
+1
View File
@@ -1690,6 +1690,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
}
}else if( bStopAtNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq);
sqlite3ExprCacheRemove(pParse, regBase+nEq, 1);
endEq = 0;
nConstraint++;
}
+14
View File
@@ -68,4 +68,18 @@ ifcapable incrblob {
} {SQLITE_CONSTRAINT}
}
ifcapable stat4 {
do_execsql_test 3.0 {
CREATE TABLE p4 (id INTEGER NOT NULL PRIMARY KEY);
INSERT INTO p4 VALUES(1), (2), (3);
CREATE TABLE c4(x INTEGER REFERENCES p4(id) DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX c4_x ON c4(x);
INSERT INTO c4 VALUES(1), (2), (3);
ANALYZE;
INSERT INTO p4(id) VALUES(4);
}
}
finish_test
+62 -58
View File
@@ -15,7 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !icu {
ifcapable !icu&&!icu_collations {
finish_test
return
}
@@ -35,54 +35,57 @@ proc test_expr {name settings expr result} {
} $settings $expr] $result
}
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
ifcapable icu {
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
}
#--------------------------------------------------------------------
# Test the collation sequence function.
@@ -124,22 +127,23 @@ do_test icu-4.3 {
#
# http://src.chromium.org/viewvc/chrome/trunk/src/third_party/sqlite/icu-regexp.patch?revision=34807&view=markup
#
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.4 { SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
do_catchsql_test icu-5.5 { SELECT 'abc' REGEXP, 1 } {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
ifcapable icu {
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.4 {SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
}
}
finish_test
+17
View File
@@ -150,4 +150,21 @@ do_execsql_test 502 {
SELECT j FROM t502 WHERE i IN (1,2,3,4,5) ORDER BY j LIMIT 3;
} {1 3 4}
# Ticket https://www.sqlite.org/src/info/123c9ba32130a6c9 2017-12-13
# Incorrect result when an idnex is used for an ordered join.
#
# This test case is in the limit2.test module because the problem was first
# exposed by check-in https://www.sqlite.org/src/info/559733b09e which
# implemented the ORDER BY LIMIT optimization that limit2.test strives to
# test.
#
do_execsql_test 600 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1,2);
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(x, y); INSERT INTO t2 VALUES(1,3);
CREATE INDEX t1ab ON t1(a,b);
SELECT y FROM t1, t2 WHERE a=x AND b<=y ORDER BY b DESC;
} {3}
finish_test
+5
View File
@@ -15,6 +15,11 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix mjournal
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
# Test that nothing bad happens if a journal file contains a pointer to
# a master journal file that does not have a "-" in the name. At one point
# this was causing a segfault on unix.
+3 -2
View File
@@ -86,9 +86,10 @@ proc test_set {args} {
#
set alltests [list]
foreach f [glob $testdir/*.test] { lappend alltests [file tail $f] }
foreach f [glob -nocomplain \
$testdir/../ext/rtree/*.test \
foreach f [glob -nocomplain \
$testdir/../ext/rtree/*.test \
$testdir/../ext/fts5/test/*.test \
$testdir/../ext/expert/*.test \
$testdir/../ext/lsm1/test/*.test \
] {
lappend alltests $f
+6 -2
View File
@@ -17,8 +17,12 @@ source $testdir/tester.tcl
unset -nocomplain DEFAULT_SECDEL
set DEFAULT_SECDEL 0
ifcapable secure_delete {
set DEFAULT_SECDEL 1
ifcapable fast_secure_delete {
set DEFAULT_SECDEL 2
} else {
ifcapable secure_delete {
set DEFAULT_SECDEL 1
}
}
+8
View File
@@ -93,6 +93,14 @@ foreach {tn schema output} {
} {
}
10 {
CREATE TABLE parent (id INTEGER PRIMARY KEY);
CREATE TABLE child2 (id INT PRIMARY KEY, parentID INT REFERENCES parent)
WITHOUT ROWID;
} {
CREATE INDEX 'child2_parentID' ON 'child2'('parentID'); --> parent(id)
}
} {
forcedelete test.db
sqlite3 db test.db
+100
View File
@@ -0,0 +1,100 @@
# 2016 September 23
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The focus
# of this file is the sqlite3_snapshot_xxx() APIs.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !snapshot {finish_test; return}
set testprefix snapshot3
# This test does not work with the inmemory_journal permutation. The reason
# is that each connection opened as part of this permutation executes
# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
# and there are one or more existing connections.
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
#-------------------------------------------------------------------------
# This block of tests verifies that it is not possible to wrap the wal
# file - using a writer or a "PRAGMA wal_checkpoint = TRUNCATE" - while
# there is an open snapshot transaction (transaction opened using
# sqlite3_snapshot_open()).
#
do_execsql_test 1.0 {
CREATE TABLE t1(y);
PRAGMA journal_mode = wal;
INSERT INTO t1 VALUES(1);
INSERT INTO t1 VALUES(2);
INSERT INTO t1 VALUES(3);
INSERT INTO t1 VALUES(4);
} {wal}
do_test 1.1 {
sqlite3 db2 test.db
sqlite3 db3 test.db
execsql {SELECT * FROM sqlite_master} db2
execsql {SELECT * FROM sqlite_master} db3
db2 trans { set snap [sqlite3_snapshot_get_blob db2 main] }
db2 eval { SELECT * FROM t1 }
} {1 2 3 4}
do_test 1.2 {
execsql BEGIN db2
sqlite3_snapshot_open_blob db2 main $snap
db2 eval { SELECT * FROM t1 }
} {1 2 3 4}
do_test 1.2 {
execsql END db2
execsql { PRAGMA wal_checkpoint }
execsql BEGIN db2
sqlite3_snapshot_open_blob db2 main $snap
db2 eval { SELECT * FROM t1 }
} {1 2 3 4}
set sz [file size test.db-wal]
do_test 1.3 {
execsql { PRAGMA wal_checkpoint = truncate }
file size test.db-wal
} $sz
do_test 1.4 {
execsql BEGIN db3
list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
} {0 {}}
do_test 1.5 {
db3 eval { SELECT * FROM t1; END }
} {1 2 3 4}
do_test 1.6 {
db2 eval { SELECT * FROM t1; END }
} {1 2 3 4}
do_test 1.7 {
execsql { PRAGMA wal_checkpoint = truncate }
file size test.db-wal
} 0
do_test 1.8 {
execsql BEGIN db3
list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg
} {1 SQLITE_BUSY_SNAPSHOT}
finish_test
+1 -1
View File
@@ -213,7 +213,7 @@ do_catchsql_test 3.1 {
("test.db2", "t1", 11, 20)
', 'fetch_db_no_such_function'
);
} {1 {no such function: fetch_db_no_such_function}}
} {1 {sql error: no such function: fetch_db_no_such_function}}
do_catchsql_test 3.2 {
CREATE VIRTUAL TABLE temp.xyz USING swarmvtab(
+1 -1
View File
@@ -14,7 +14,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix swarmvtab
set testprefix swarmvtab2
do_not_use_codec
ifcapable !vtab {
+233
View File
@@ -0,0 +1,233 @@
# 2017-07-15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. The
# focus of this file is the "swarmvtab" extension
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix swarmvtab3
do_not_use_codec
ifcapable !vtab {
finish_test
return
}
load_static_extension db unionvtab
set nFile $sqlite_open_file_count
do_execsql_test 1.0 {
CREATE TEMP TABLE swarm(id, tbl, minval, maxval);
}
# Set up 100 databases with filenames "remote_test.dbN", where N is between
# 0 and 99.
do_test 1.1 {
for {set i 0} {$i < 100} {incr i} {
set file remote_test.db$i
forcedelete $file
forcedelete test.db$i
sqlite3 rrr $file
rrr eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES($i, $i);
}
rrr close
db eval {
INSERT INTO swarm VALUES($i, 't1', $i, $i);
}
set ::dbcache(test.db$i) 0
}
} {}
proc missing_db {filename} {
set remote "remote_$filename"
forcedelete $filename
file copy $remote $filename
}
db func missing_db missing_db
proc openclose_db {filename bClose} {
if {$bClose} {
incr ::dbcache($filename) -1
} else {
incr ::dbcache($filename) 1
}
if {$::dbcache($filename)==0} {
forcedelete $filename
}
}
db func openclose_db openclose_db
proc check_dbcache {} {
set n 0
for {set i 0} {$i<100} {incr i} {
set exists [file exists test.db$i]
if {$exists!=($::dbcache(test.db$i)!=0)} {
error "inconsistent ::dbcache and disk"
}
incr n $exists
}
return $n
}
foreach {tn nMaxOpen cvt} {
1 5 {
CREATE VIRTUAL TABLE temp.s USING swarmvtab(
'SELECT :prefix || id, tbl, minval, minval FROM swarm',
:prefix='test.db',
missing=missing_db,
openclose=openclose_db,
maxopen=5
)
}
2 3 {
CREATE VIRTUAL TABLE temp.s USING swarmvtab(
'SELECT :prefix || id, tbl, minval, minval FROM swarm',
:prefix='test.db',
missing = 'missing_db',
openclose=[openclose_db],
maxopen = 3
)
}
3 1 {
CREATE VIRTUAL TABLE temp.s USING swarmvtab(
'SELECT :prefix||''.''||:suffix||id, tbl, minval, minval FROM swarm',
:prefix=test, :suffix=db,
missing = 'missing_db',
openclose=[openclose_db],
maxopen = 1
)
}
} {
execsql { DROP TABLE IF EXISTS s }
do_execsql_test 1.$tn.1 $cvt
do_execsql_test 1.$tn.2 {
SELECT b FROM s WHERE a<10;
} {0 1 2 3 4 5 6 7 8 9}
do_test 1.$tn.3 { check_dbcache } $nMaxOpen
do_execsql_test 1.$tn.4 {
SELECT b FROM s WHERE (b%10)=0;
} {0 10 20 30 40 50 60 70 80 90}
do_test 1.$tn.5 { check_dbcache } $nMaxOpen
}
execsql { DROP TABLE IF EXISTS s }
for {set i 0} {$i < 100} {incr i} {
forcedelete remote_test.db$i
}
#----------------------------------------------------------------------------
#
do_execsql_test 2.0 {
DROP TABLE IF EXISTS swarm;
CREATE TEMP TABLE swarm(file, tbl, minval, maxval, ctx);
}
catch { array unset ::dbcache }
# Set up 100 databases with filenames "remote_test.dbN", where N is a
# random integer between 0 and 1,000,000
# 0 and 99.
do_test 2.1 {
for {set i 0} {$i < 100} {incr i} {
while 1 {
set ctx [expr abs(int(rand() *1000000))]
if {[info exists ::dbcache($ctx)]==0} break
}
set file test_remote.db$ctx
forcedelete $file
forcedelete test.db$i
sqlite3 rrr $file
rrr eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES($i, $i);
}
rrr close
db eval {
INSERT INTO swarm VALUES('test.db' || $i, 't1', $i, $i, $file)
}
set ::dbcache(test.db$i) 0
}
} {}
proc missing_db {filename ctx} {
file copy $ctx $filename
}
db func missing_db missing_db
proc openclose_db {filename ctx bClose} {
if {$bClose} {
incr ::dbcache($filename) -1
} else {
incr ::dbcache($filename) 1
}
if {$::dbcache($filename)==0} {
forcedelete $filename
}
}
db func openclose_db openclose_db
proc check_dbcache {} {
set n 0
foreach k [array names ::dbcache] {
set exists [file exists $k]
if {$exists!=($::dbcache($k)!=0)} {
error "inconsistent ::dbcache and disk ($k)"
}
incr n $exists
}
return $n
}
foreach {tn nMaxOpen cvt} {
2 5 {
CREATE VIRTUAL TABLE temp.s USING swarmvtab(
'SELECT file, tbl, minval, minval, ctx FROM swarm',
missing=missing_db,
openclose=openclose_db,
maxopen=5
)
}
} {
execsql { DROP TABLE IF EXISTS s }
do_execsql_test 1.$tn.1 $cvt
do_execsql_test 1.$tn.2 {
SELECT b FROM s WHERE a<10;
} {0 1 2 3 4 5 6 7 8 9}
do_test 1.$tn.3 { check_dbcache } $nMaxOpen
do_execsql_test 1.$tn.4 {
SELECT b FROM s WHERE (b%10)=0;
} {0 10 20 30 40 50 60 70 80 90}
do_test 1.$tn.5 { check_dbcache } $nMaxOpen
}
db close
forcedelete {*}[glob test_remote.db*]
finish_test
+13
View File
@@ -62,4 +62,17 @@ do_execsql_test 200 {
SELECT b FROM t2 ORDER BY b;
} {20202 20203 20302 20303 30202 30203 30302 30303 40202 40203 40302 40303 50202 50203 50302 50303}
# At one point the following was causing an assert() to fail.
#
do_execsql_test 300 {
CREATE TABLE t4(x);
CREATE TRIGGER tr4 AFTER INSERT ON t4 BEGIN
SELECT 0x2147483648e0e0099 AS y WHERE y;
END;
}
do_catchsql_test 310 {
INSERT INTO t4 VALUES(1);
} {1 {hex literal too big: 0x2147483648e0e0099}}
finish_test
+23 -9
View File
@@ -52,21 +52,21 @@ do_test 1.1 {
set ::locks [list]
sqlite3 db test.db -vfs T
execsql { SELECT * FROM x }
lrange $::locks 0 3
} [list {0 1 lock exclusive} {1 7 lock exclusive} \
{1 7 unlock exclusive} {0 1 unlock exclusive} \
lrange $::locks 0 5
} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
{1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
]
do_test 1.2 {
db close
set ::locks [list]
sqlite3 db test.db -vfs T
execsql { SELECT * FROM x }
lrange $::locks 0 3
} [list {0 1 lock exclusive} {1 7 lock exclusive} \
{1 7 unlock exclusive} {0 1 unlock exclusive} \
lrange $::locks 0 5
} [list {0 1 lock exclusive} {1 2 lock exclusive} {4 4 lock exclusive} \
{1 2 unlock exclusive} {4 4 unlock exclusive} {0 1 unlock exclusive} \
]
proc lock_callback {method filename handle lock} {
if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY }
if {$lock == "1 2 lock exclusive"} { return SQLITE_BUSY }
return SQLITE_OK
}
puts "# Warning: This next test case causes SQLite to call xSleep(1) 100 times."
@@ -90,6 +90,18 @@ do_test 1.4 {
sqlite3 db test.db -vfs T
catchsql { SELECT * FROM x }
} {1 {locking protocol}}
puts "# Warning: Third time!"
proc lock_callback {method filename handle lock} {
if {$lock == "4 4 lock exclusive"} { return SQLITE_BUSY }
return SQLITE_OK
}
do_test 1.5 {
db close
set ::locks [list]
sqlite3 db test.db -vfs T
catchsql { SELECT * FROM x }
} {1 {locking protocol}}
db close
T delete
@@ -135,13 +147,14 @@ T filter xShmLock
T script lock_callback
proc lock_callback {method file handle spec} {
if {$spec == "1 7 unlock exclusive"} {
if {$spec == "1 2 unlock exclusive"} {
T filter {}
set ::r [catchsql { SELECT * FROM b } db2]
}
}
sqlite3 db test.db
sqlite3 db2 test.db
puts "# Warning: Another slow test!"
do_test 2.5 {
execsql { SELECT * FROM b }
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
@@ -157,12 +170,13 @@ sqlite3 db2 test.db
T filter xShmLock
T script lock_callback
proc lock_callback {method file handle spec} {
if {$spec == "1 7 unlock exclusive"} {
if {$spec == "1 2 unlock exclusive"} {
T filter {}
set ::r [catchsql { SELECT * FROM b } db2]
}
}
unset ::r
puts "# Warning: Last one!"
do_test 2.7 {
execsql { SELECT * FROM b }
} {Tehran Qom Markazi Qazvin Gilan Ardabil}
+3 -2
View File
@@ -262,8 +262,9 @@ do_multiclient_test tn {
}
} {500}
do_test $TN.4.2.2 {
file size test.db-wal
} {461152}
set sz [file size test.db-wal]
expr {$sz>400000 && $sz<500000}
} {1}
do_test $TN.4.2.4 {
file_control_persist_wal db 1; db close
+10 -2
View File
@@ -651,10 +651,18 @@ static void yy_accept(yyParser*); /* Forward Declaration */
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
**
** The yyLookahead and yyLookaheadToken parameters provide reduce actions
** access to the lookahead token (if any). The yyLookahead will be YYNOCODE
** if the lookahead token has already been consumed. As this procedure is
** only called from one place, optimizing compilers will in-line it, which
** means that the extra parameters have no performance impact.
*/
static void yy_reduce(
yyParser *yypParser, /* The parser */
unsigned int yyruleno /* Number of the rule by which to reduce */
unsigned int yyruleno, /* Number of the rule by which to reduce */
int yyLookahead, /* Lookahead token, or YYNOCODE if none */
ParseTOKENTYPE yyLookaheadToken /* Value of the lookahead token */
){
int yygoto; /* The next state */
int yyact; /* The next action */
@@ -853,7 +861,7 @@ void Parse(
#endif
yymajor = YYNOCODE;
}else if( yyact <= YY_MAX_REDUCE ){
yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
yy_reduce(yypParser,yyact-YY_MIN_REDUCE,yymajor,yyminor);
}else{
assert( yyact == YY_ERROR_ACTION );
yyminorunion.yy0 = yyminor;