Merge in all changes found in the version 3.7.9 release candidate.

FossilOrigin-Name: 23580718e1c15ddb89682d0e7566da4d7276bfe9
This commit is contained in:
drh 2011-10-31 14:34:31 +00:00
commit f004e1d69e
28 changed files with 567 additions and 691 deletions

178
ext/fts3/README.content Normal file
View File

@ -0,0 +1,178 @@
FTS4 CONTENT OPTION
Normally, in order to create a full-text index on a dataset, the FTS4
module stores a copy of all indexed documents in a specially created
database table.
As of SQLite version 3.7.9, FTS4 supports a new option - "content" -
designed to extend FTS4 to support the creation of full-text indexes where:
* The indexed documents are not stored within the SQLite database
at all (a "contentless" FTS4 table), or
* The indexed documents are stored in a database table created and
managed by the user (an "external content" FTS4 table).
Because the indexed documents themselves are usually much larger than
the full-text index, the content option can sometimes be used to achieve
significant space savings.
CONTENTLESS FTS4 TABLES
In order to create an FTS4 table that does not store a copy of the indexed
documents at all, the content option should be set to an empty string.
For example, the following SQL creates such an FTS4 table with three
columns - "a", "b", and "c":
CREATE VIRTUAL TABLE t1 USING fts4(content="", a, b, c);
Data can be inserted into such an FTS4 table using an INSERT statements.
However, unlike ordinary FTS4 tables, the user must supply an explicit
integer docid value. For example:
-- This statement is Ok:
INSERT INTO t1(docid, a, b, c) VALUES(1, 'a b c', 'd e f', 'g h i');
-- This statement causes an error, as no docid value has been provided:
INSERT INTO t1(a, b, c) VALUES('j k l', 'm n o', 'p q r');
It is not possible to UPDATE or DELETE a row stored in a contentless FTS4
table. Attempting to do so is an error.
Contentless FTS4 tables also support SELECT statements. However, it is
an error to attempt to retrieve the value of any table column other than
the docid column. The auxiliary function matchinfo() may be used, but
snippet() and offsets() may not. For example:
-- The following statements are Ok:
SELECT docid FROM t1 WHERE t1 MATCH 'xxx';
SELECT docid FROM t1 WHERE a MATCH 'xxx';
SELECT matchinfo(t1) FROM t1 WHERE t1 MATCH 'xxx';
-- The following statements all cause errors, as the value of columns
-- other than docid are required to evaluate them.
SELECT * FROM t1;
SELECT a, b FROM t1 WHERE t1 MATCH 'xxx';
SELECT docid FROM t1 WHERE a LIKE 'xxx%';
SELECT snippet(t1) FROM t1 WHERE t1 MATCH 'xxx';
Errors related to attempting to retrieve column values other than docid
are runtime errors that occur within sqlite3_step(). In some cases, for
example if the MATCH expression in a SELECT query matches zero rows, there
may be no error at all even if a statement does refer to column values
other than docid.
EXTERNAL CONTENT FTS4 TABLES
An "external content" FTS4 table is similar to a contentless table, except
that if evaluation of a query requires the value of a column other than
docid, FTS4 attempts to retrieve that value from a table (or view, or
virtual table) nominated by the user (hereafter referred to as the "content
table"). The FTS4 module never writes to the content table, and writing
to the content table does not affect the full-text index. It is the
responsibility of the user to ensure that the content table and the
full-text index are consistent.
An external content FTS4 table is created by setting the content option
to the name of a table (or view, or virtual table) that may be queried by
FTS4 to retrieve column values when required. If the nominated table does
not exist, then an external content table behaves in the same way as
a contentless table. For example:
CREATE TABLE t2(id INTEGER PRIMARY KEY, a, b, c);
CREATE VIRTUAL TABLE t3 USING fts4(content="t2", a, c);
Assuming the nominated table does exist, then its columns must be the same
as or a superset of those defined for the FTS table.
When a users query on the FTS table requires a column value other than
docid, FTS attempts to read this value from the corresponding column of
the row in the content table with a rowid value equal to the current FTS
docid. Or, if such a row cannot be found in the content table, a NULL
value is used instead. For example:
CREATE TABLE t2(id INTEGER PRIMARY KEY, a, b, c, d);
CREATE VIRTUAL TABLE t3 USING fts4(content="t2", b, c);
INSERT INTO t2 VALUES(2, 'a b', 'c d', 'e f');
INSERT INTO t2 VALUES(3, 'g h', 'i j', 'k l');
INSERT INTO t3(docid, b, c) SELECT id, b, c FROM t2;
-- The following query returns a single row with two columns containing
-- the text values "i j" and "k l".
--
-- The query uses the full-text index to discover that the MATCH
-- term matches the row with docid=3. It then retrieves the values
-- of columns b and c from the row with rowid=3 in the content table
-- to return.
--
SELECT * FROM t3 WHERE t3 MATCH 'k';
-- Following the UPDATE, the query still returns a single row, this
-- time containing the text values "xxx" and "yyy". This is because the
-- full-text index still indicates that the row with docid=3 matches
-- the FTS4 query 'k', even though the documents stored in the content
-- table have been modified.
--
UPDATE t2 SET b = 'xxx', c = 'yyy' WHERE rowid = 3;
SELECT * FROM t3 WHERE t3 MATCH 'k';
-- Following the DELETE below, the query returns one row containing two
-- NULL values. NULL values are returned because FTS is unable to find
-- a row with rowid=3 within the content table.
--
DELETE FROM t2;
SELECT * FROM t3 WHERE t3 MATCH 'k';
When a row is deleted from an external content FTS4 table, FTS4 needs to
retrieve the column values of the row being deleted from the content table.
This is so that FTS4 can update the full-text index entries for each token
that occurs within the deleted row to indicate that that row has been
deleted. If the content table row cannot be found, or if it contains values
inconsistent with the contents of the FTS index, the results can be difficult
to predict. The FTS index may be left containing entries corresponding to the
deleted row, which can lead to seemingly nonsensical results being returned
by subsequent SELECT queries. The same applies when a row is updated, as
internally an UPDATE is the same as a DELETE followed by an INSERT.
Instead of writing separately to the full-text index and the content table,
some users may wish to use database triggers to keep the full-text index
up to date with respect to the set of documents stored in the content table.
For example, using the tables from earlier examples:
CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_bd BEFORE DELETE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_bu AFTER UPDATE ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
CREATE TRIGGER t2_bd AFTER INSERT ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
The DELETE trigger must be fired before the actual delete takes place
on the content table. This is so that FTS4 can still retrieve the original
values in order to update the full-text index. And the INSERT trigger must
be fired after the new row is inserted, so as to handle the case where the
rowid is assigned automatically within the system. The UPDATE trigger must
be split into two parts, one fired before and one after the update of the
content table, for the same reasons.
FTS4 features a special command similar to the 'optimize' command that
deletes the entire full-text index and rebuilds it based on the current
set of documents in the content table. Assuming again that "t3" is the
name of the external content FTS4 table, the command is:
INSERT INTO t3(t3) VALUES('rebuild');
This command may also be used with ordinary FTS4 tables, although it may
only be useful if the full-text index has somehow become corrupt. It is an
error to attempt to rebuild the full-text index maintained by a contentless
FTS4 table.

View File

@ -1,5 +1,5 @@
C Merge\sthe\slatest\strunk\senhancements\sinto\sthe\ssessions\sbranch.
D 2011-10-21T17:08:23.879
C Merge\sin\sall\schanges\sfound\sin\sthe\sversion\s3.7.9\srelease\scandidate.
D 2011-10-31T14:34:31.942
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -59,6 +59,7 @@ F ext/fts2/fts2_tokenizer.c 26e993a00b2bd5b6e73c155597361710b12ffe25
F ext/fts2/fts2_tokenizer.h a7e46462d935a314b2682287f12f27530a3ee08e
F ext/fts2/fts2_tokenizer1.c 0123d21078e053bd98fd6186c5c6dc6d67969f2e
F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
@ -130,7 +131,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
F src/analyze.c 682fd999a01c897a682365a459190758b83de836
F src/analyze.c 5a1db16a651ce6310c8b046b2cbb736e030e14b9
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 4368158da74d4711888e03264105c5c527d76caf
@ -139,10 +140,10 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 32199e2d939233ade25340eaba450f818b37c079
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
F src/build.c ae152efb9c2d6615b14adb7a5f2c51483d4d55df
F src/build.c 8af67a08a852ff4c63701963cb1ab7166f577814
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 829f3261d3db48e3d87891bc887208734734c2e4
F src/ctime.c a9c26822515f81ec21588cbb482ca6724be02e33
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 614d6e012aa5b624e78f3b556243497825de196b
F src/expr.c fbf116f90cabc917ae50bba24a73a0b55519a0c8
@ -193,9 +194,9 @@ F src/resolve.c 365ab1c870e38596d6869e76fb544fe6e4ffc809
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 80f3ac44a8514b1d107b80f5df4a424ae059d2b6
F src/shell.c f0ab793261ab045a0b8c47fa2707e8a894d2898f
F src/sqlite.h.in 42693f5fc57345ee4bfc9ab4b65a1637c8fd2034
F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
F src/sqliteInt.h bdf2d6a2c2908864fd75a242b35ded2cf3a0f395
F src/sqlite.h.in 4db67e21b8e05df60dedfc34a25ca1acf6002f48
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h 3772c4ab4a5d04ca99afabdb49278d74f74d2403
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@ -207,13 +208,13 @@ F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
F src/test5.c e1a19845625144caf038031234a12185e40d315c
F src/test6.c 3191b4ab964a144230ff9ef96c093520375c7b2a
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
F src/test8.c 6b1d12912a04fe6fca8c45bb9c3ea022f4352228
F src/test8.c 99f70341d6ec480313775127f4cd14b4a47db557
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c b36ab29f3d9ed4453c989717ef99b1f3c52f443e
F src/test_config.c 7c1ebc097eee4aec81a0fcaef67e64ffb7217f25
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
@ -250,32 +251,31 @@ F src/update.c 7509519281d566553cb2e8561541d49a2c054ed4
F src/utf.c 890c67dcfcc7a74623c95baac7535aadfe265e84
F src/util.c df83983bd57057df4951516880066b42b7055269
F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
F src/vdbe.c 9cccccebf82571837b03e0b7bdc22a2651c368c5
F src/vdbe.c f3d112340d6f9b1acae32673df2e27e782453e7c
F src/vdbe.h 226d4bc726b3597c35be155a4342db290601d67c
F src/vdbeInt.h 1400515b37a4863cdda4601abc0f76eca846c9f5
F src/vdbeapi.c c969d467817ca90f99f3d3b46d115fbec08aeb4c
F src/vdbeaux.c c2e9565d942bf9258155f62ec4c80197d5e449f5
F src/vdbeInt.h 09dacf6f91da9a386b5427d06a4154aa66a8866d
F src/vdbeapi.c 0dd7815837230957d5547d9f573c25a92bc792ce
F src/vdbeaux.c 6836b38d0bd607b5ff20796c4c29c07209a935b5
F src/vdbeblob.c 11248c6362389569764682eb0f59ce910f3cc381
F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c 5d0dc3d5fd54878cc8d6d28eb41deb8d5885b114
F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
F src/wal.c 9658df8d404b82e6b2d40fd05944463214e2d935
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 922145a39cf91a5dbb83bbc54f0e316f52023fa2
F src/where.c 7c85f4c93058e27100d404f0777aaeb0d1b296ae
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 52fc8dee494092031a556911d404ca30a749a30b
F test/alter.test 54912d932309df2e4f62aeb47169c2ff740e53ed
F test/alter.test 66f5818f9848c4f22de022a345fae25bcd30f8fb
F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae
F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3
F test/analyze3.test 9be0af5e23b711559e8f78c42a6c04de956cba9b
F test/analyze3.test c3c7f6c3951900c188cf94b2d5ee3246d6b3ff89
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e
F test/analyze6.test bd3625806a5ee6f7bef72d06295bd319f0290af2
@ -291,7 +291,7 @@ F test/attach2.test e54436ed956d3d88bdee61221da59bf3935a0966
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
F test/attach4.test 53bf502f17647c6d6c5add46dda6bac8b6f4665c
F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
F test/auth.test ac996c81ad910148606f5c7e3b3f85d47c29960f
F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f
F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
@ -405,6 +405,7 @@ F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad
F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
F test/eqp.test f14fadd76da53405e9885e2431cacf7191d83cdb
F test/errmsg.test 3bb606db9d040cc6854459f8f5e5a2bcd9b7fd2a
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb
F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6
@ -418,7 +419,7 @@ F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
F test/fkey2.test 080969fe219b3b082b0e097ac18c6af2e5b0631f
F test/fkey3.test 5ec899d12b13bcf1e9ef40eff7fb692fdb91392e
F test/fkey4.test c6c8f9f9be885f95c85c7bceb26f243ad906fd49
F test/fkey_malloc.test a5ede29bd2f6e56dea78c3d43fb86dd696c068c8
F test/fkey_malloc.test c3a12acd053c976de09036498eef09b83afa4a80
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
@ -485,10 +486,11 @@ F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
F test/fts3d.test bf640d79722b720fa1c81834c48cdaa45d531b1a
F test/fts3defer.test 2ea3fa028f8d9523f9c33dd8acc4555d567ea4ac
F test/fts3defer2.test 35867d33ba6db03f6c73bd6f5fc333ae14f68c81
F test/fts3drop.test 1b906e293d6773812587b3dc458cb9e8f3f0c297
F test/fts3e.test 1f6c6ac9cc8b772ca256e6b22aaeed50c9350851
F test/fts3expr.test 5e745b2b6348499d9ef8d59015de3182072c564c
F test/fts3expr2.test 18da930352e5693eaa163a3eacf96233b7290d1a
F test/fts3fault.test f83e556465bb69dc8bc676339eca408dce4ca246
F test/fts3fault.test cb72dccb0a3b9f730f16c5240f3fcb9303eb1660
F test/fts3fault2.test b62a2bc843c20414405f80e5eeb78e39bc68fe53
F test/fts3first.test dbdedd20914c8d539aa3206c9b34a23775644641
F test/fts3malloc.test b86ea33db9e8c58c0c2f8027a9fcadaf6a1568be
@ -501,7 +503,7 @@ F test/fts3shared.test 8bb266521d7c5495c0ae522bb4d376ad5387d4a2
F test/fts3snippet.test 8e956051221a34c7daeb504f023cb54d5fa5a8b2
F test/fts3sort.test 95be0b19d7e41c44b29014f13ea8bddd495fd659
F test/fts4aa.test 6e7f90420b837b2c685f3bcbe84c868492d40a68
F test/fts4content.test c5f531ecfc3d446b90032cae212549dbbb18dd78
F test/fts4content.test 2624253c7e5a32d0c0d51f776dcd4526f0a51097
F test/func.test 6c5ce11e3a0021ca3c0649234e2d4454c89110ca
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
@ -577,7 +579,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test 8c727fe29fccd280cbf8f6acf08bd10b76beaf34
F test/malloc.test bc745155ff4252d4f35ec8316625b0dfe2abc659
F test/malloc3.test de8eca0c3e748878845fdca3663ec4b642073caf
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test 30dc30b57fa22552eba0d8c95210d96c3d958a39
@ -886,7 +888,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 7701bb609fe8bf6535514e8b849a309e8f00573b
F test/view.test b182a67ec43f490b156b5a710827a341be83dd17
F test/vtab1.test b40b7e531dea8f0f7e78c76ff96eed103f58d015
F test/vtab1.test 12fbb309ce830c4064e44f275eb02a65c2780076
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
F test/vtab3.test baad99fd27217f5d6db10660522e0b7192446de1
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
@ -985,7 +987,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
P 403431cac6b039b0693915c5422f08dc60dae230 76de9914bed11abda3898928633ad09d5a284f84
R ab14a959a3d450010ae943a82abd757a
P 8baef58170ff851d0c4387a6888f59b487b4f33c 6635cd9a7714b681dd8aa96e90be462a40d10178
R 88557586b3e0b84a1620603b302d896a
U drh
Z 7ff2c714c610eb8c2779c328e2695599
Z 16ec16c4d6fe744468506e061de572a3

View File

@ -1 +1 @@
8baef58170ff851d0c4387a6888f59b487b4f33c
23580718e1c15ddb89682d0e7566da4d7276bfe9

View File

@ -119,16 +119,16 @@
/*
** This routine generates code that opens the sqlite_stat1 table for
** writing with cursor iStatCur. If the library was built with the
** SQLITE_ENABLE_STAT2 macro defined, then the sqlite_stat2 table is
** SQLITE_ENABLE_STAT3 macro defined, then the sqlite_stat3 table is
** opened for writing using cursor (iStatCur+1)
**
** If the sqlite_stat1 tables does not previously exist, it is created.
** Similarly, if the sqlite_stat2 table does not exist and the library
** is compiled with SQLITE_ENABLE_STAT2 defined, it is created.
** Similarly, if the sqlite_stat3 table does not exist and the library
** is compiled with SQLITE_ENABLE_STAT3 defined, it is created.
**
** Argument zWhere may be a pointer to a buffer containing a table name,
** or it may be a NULL pointer. If it is not NULL, then all entries in
** the sqlite_stat1 and (if applicable) sqlite_stat2 tables associated
** the sqlite_stat1 and (if applicable) sqlite_stat3 tables associated
** with the named table are deleted. If zWhere==0, then code is generated
** to delete all stat table entries.
*/

View File

@ -1981,7 +1981,7 @@ static void destroyTable(Parse *pParse, Table *pTab){
}
/*
** Remove entries from the sqlite_stat1 and sqlite_stat2 tables
** Remove entries from the sqlite_statN tables (for N in (1,2,3))
** after a DROP INDEX or DROP TABLE command.
*/
static void sqlite3ClearStatTables(
@ -1990,18 +1990,15 @@ static void sqlite3ClearStatTables(
const char *zType, /* "idx" or "tbl" */
const char *zName /* Name of index or table */
){
static const char *azStatTab[] = {
"sqlite_stat1",
"sqlite_stat2",
"sqlite_stat3",
};
int i;
const char *zDbName = pParse->db->aDb[iDb].zName;
for(i=0; i<ArraySize(azStatTab); i++){
if( sqlite3FindTable(pParse->db, azStatTab[i], zDbName) ){
for(i=1; i<=3; i++){
char zTab[24];
sqlite3_snprintf(sizeof(zTab),zTab,"sqlite_stat%d",i);
if( sqlite3FindTable(pParse->db, zTab, zDbName) ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE %s=%Q",
zDbName, azStatTab[i], zType, zName
zDbName, zTab, zType, zName
);
}
}

View File

@ -114,9 +114,6 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_ENABLE_RTREE
"ENABLE_RTREE",
#endif
#ifdef SQLITE_ENABLE_STAT2
"ENABLE_STAT2",
#endif
#ifdef SQLITE_ENABLE_STAT3
"ENABLE_STAT3",
#endif

View File

@ -741,7 +741,7 @@ struct sqlite3_io_methods {
** retry counts and intervals for certain disk I/O operations for the
** windows [VFS] in order to work to provide robustness against
** anti-virus programs. By default, the windows VFS will retry file read,
** file write, and file delete opertions up to 10 times, with a delay
** file write, and file delete operations up to 10 times, with a delay
** of 25 milliseconds before the first retry and with the delay increasing
** by an additional 25 milliseconds with each subsequent retry. This
** opcode allows those to values (10 retries and 25 milliseconds of delay)

View File

@ -49,8 +49,10 @@ struct sqlite3_api_routines {
int (*busy_timeout)(sqlite3*,int ms);
int (*changes)(sqlite3*);
int (*close)(sqlite3*);
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const char*));
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,
int eTextRep,const void*));
const void * (*column_blob)(sqlite3_stmt*,int iCol);
int (*column_bytes)(sqlite3_stmt*,int iCol);
int (*column_bytes16)(sqlite3_stmt*,int iCol);
@ -75,10 +77,18 @@ struct sqlite3_api_routines {
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
int (*complete)(const char*sql);
int (*complete16)(const void*sql);
int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
int (*create_collation)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_collation16)(sqlite3*,const void*,int,void*,
int(*)(void*,int,const void*,int,const void*));
int (*create_function)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_function16)(sqlite3*,const void*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*));
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
int (*data_count)(sqlite3_stmt*pStmt);
sqlite3 * (*db_handle)(sqlite3_stmt*);
@ -123,16 +133,19 @@ struct sqlite3_api_routines {
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
void (*result_value)(sqlite3_context*,sqlite3_value*);
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,
const char*,const char*),void*);
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
char * (*snprintf)(int,char*,const char*,...);
int (*step)(sqlite3_stmt*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,
char const**,char const**,int*,int*,int*);
void (*thread_cleanup)(void);
int (*total_changes)(sqlite3*);
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,
sqlite_int64),void*);
void * (*user_data)(sqlite3_context*);
const void * (*value_blob)(sqlite3_value*);
int (*value_bytes)(sqlite3_value*);
@ -154,15 +167,19 @@ struct sqlite3_api_routines {
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
int (*clear_bindings)(sqlite3_stmt*);
/* Added by 3.4.1 */
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,
void (*xDestroy)(void *));
/* Added by 3.5.0 */
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
int (*blob_bytes)(sqlite3_blob*);
int (*blob_close)(sqlite3_blob*);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,
int,sqlite3_blob**);
int (*blob_read)(sqlite3_blob*,void*,int,int);
int (*blob_write)(sqlite3_blob*,const void*,int,int);
int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
int (*create_collation_v2)(sqlite3*,const char*,int,void*,
int(*)(void*,int,const void*,int,const void*),
void(*)(void*));
int (*file_control)(sqlite3*,const char*,int,void*);
sqlite3_int64 (*memory_highwater)(int);
sqlite3_int64 (*memory_used)(void);
@ -198,7 +215,11 @@ struct sqlite3_api_routines {
int (*backup_step)(sqlite3_backup*,int);
const char *(*compileoption_get)(int);
int (*compileoption_used)(const char*);
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*),void(*xDestroy)(void*));
int (*create_function_v2)(sqlite3*,const char*,int,int,void*,
void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
void (*xFinal)(sqlite3_context*),
void(*xDestroy)(void*));
int (*db_config)(sqlite3*,int,...);
sqlite3_mutex *(*db_mutex)(sqlite3*);
int (*db_status)(sqlite3*,int,int*,int*,int);

View File

@ -76,13 +76,6 @@
#include <inttypes.h>
#endif
/*
** The number of samples of an index that SQLite takes in order to
** construct a histogram of the table content when running ANALYZE
** and with SQLITE_ENABLE_STAT2
*/
#define SQLITE_INDEX_SAMPLES 10
/*
** The following macros are used to cast pointers to integers and
** integers to pointers. The way you do this varies from one compiler
@ -1522,8 +1515,9 @@ struct Index {
};
/*
** Each sample stored in the sqlite_stat2 table is represented in memory
** using a structure of this type.
** Each sample stored in the sqlite_stat3 table is represented in memory
** using a structure of this type. See documentation at the top of the
** analyze.c source file for additional information.
*/
struct IndexSample {
union {

View File

@ -1232,12 +1232,50 @@ static int echoRename(sqlite3_vtab *vtab, const char *zNewName){
return rc;
}
static int echoSavepoint(sqlite3_vtab *pVTab, int iSavepoint){
assert( pVTab );
return SQLITE_OK;
}
static int echoRelease(sqlite3_vtab *pVTab, int iSavepoint){
assert( pVTab );
return SQLITE_OK;
}
static int echoRollbackTo(sqlite3_vtab *pVTab, int iSavepoint){
assert( pVTab );
return SQLITE_OK;
}
/*
** A virtual table module that merely "echos" the contents of another
** table (like an SQL VIEW).
*/
static sqlite3_module echoModule = {
0, /* iVersion */
1, /* iVersion */
echoCreate,
echoConnect,
echoBestIndex,
echoDisconnect,
echoDestroy,
echoOpen, /* xOpen - open a cursor */
echoClose, /* xClose - close a cursor */
echoFilter, /* xFilter - configure scan constraints */
echoNext, /* xNext - advance a cursor */
echoEof, /* xEof */
echoColumn, /* xColumn - read data */
echoRowid, /* xRowid - read data */
echoUpdate, /* xUpdate - write data */
echoBegin, /* xBegin - begin transaction */
echoSync, /* xSync - sync transaction */
echoCommit, /* xCommit - commit transaction */
echoRollback, /* xRollback - rollback transaction */
echoFindFunction, /* xFindFunction - function overloading */
echoRename /* xRename - rename the table */
};
static sqlite3_module echoModuleV2 = {
2, /* iVersion */
echoCreate,
echoConnect,
echoBestIndex,
@ -1257,6 +1295,9 @@ static sqlite3_module echoModule = {
echoRollback, /* xRollback - rollback transaction */
echoFindFunction, /* xFindFunction - function overloading */
echoRename, /* xRename - rename the table */
echoSavepoint,
echoRelease,
echoRollbackTo
};
/*
@ -1284,9 +1325,18 @@ static int register_echo_module(
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
/* Virtual table module "echo" */
pMod = sqlite3_malloc(sizeof(EchoModule));
pMod->interp = interp;
sqlite3_create_module_v2(db, "echo", &echoModule, (void*)pMod, moduleDestroy);
/* Virtual table module "echo_v2" */
pMod = sqlite3_malloc(sizeof(EchoModule));
pMod->interp = interp;
sqlite3_create_module_v2(db, "echo_v2",
&echoModuleV2, (void*)pMod, moduleDestroy
);
return TCL_OK;
}

View File

@ -436,12 +436,6 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "session", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_STAT2
Tcl_SetVar2(interp, "sqlite_options", "stat2", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "stat2", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_STAT3
Tcl_SetVar2(interp, "sqlite_options", "stat3", "1", TCL_GLOBAL_ONLY);
#else

View File

@ -4356,9 +4356,8 @@ case OP_Last: { /* jump */
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
pCrsr = pC->pCursor;
if( NEVER(pCrsr==0) ){
res = 1;
}else{
res = 0;
if( ALWAYS(pCrsr!=0) ){
rc = sqlite3BtreeLast(pCrsr, &res);
}
pC->nullRow = (u8)res;

View File

@ -416,6 +416,7 @@ int sqlite3VdbeFrameRestore(VdbeFrame *);
void sqlite3VdbeMemStoreType(Mem *pMem);
void sqlite3VdbePreUpdateHook(
Vdbe *, VdbeCursor *, int, const char*, Table *, i64, int);
int sqlite3VdbeTransferError(Vdbe *p);
#ifdef SQLITE_OMIT_MERGE_SORT
# define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK

View File

@ -454,7 +454,7 @@ end_of_step:
** error has occured, then return the error code in p->rc to the
** caller. Set the error code in the database handle to the same value.
*/
rc = db->errCode = p->rc;
rc = sqlite3VdbeTransferError(p);
}
return (rc&db->errMask);
}

View File

@ -2311,6 +2311,30 @@ void sqlite3VdbeResetStepResult(Vdbe *p){
p->rc = SQLITE_OK;
}
/*
** Copy the error code and error message belonging to the VDBE passed
** as the first argument to its database handle (so that they will be
** returned by calls to sqlite3_errcode() and sqlite3_errmsg()).
**
** This function does not clear the VDBE error code or message, just
** copies them to the database handle.
*/
int sqlite3VdbeTransferError(Vdbe *p){
sqlite3 *db = p->db;
int rc = p->rc;
if( p->zErrMsg ){
u8 mallocFailed = db->mallocFailed;
sqlite3BeginBenignMalloc();
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->mallocFailed = mallocFailed;
db->errCode = rc;
}else{
sqlite3Error(db, rc, 0);
}
return rc;
}
/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
@ -2338,18 +2362,9 @@ int sqlite3VdbeReset(Vdbe *p){
** instructions yet, leave the main database error information unchanged.
*/
if( p->pc>=0 ){
if( p->zErrMsg ){
sqlite3BeginBenignMalloc();
sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT);
sqlite3EndBenignMalloc();
db->errCode = p->rc;
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
}else if( p->rc ){
sqlite3Error(db, p->rc, 0);
}else{
sqlite3Error(db, SQLITE_OK, 0);
}
sqlite3VdbeTransferError(p);
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
if( p->runOnlyOnce ) p->expired = 1;
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call

View File

@ -891,7 +891,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
VTable *pVTab = db->aVTrans[i];
const sqlite3_module *pMod = pVTab->pMod->pModule;
if( pMod->iVersion>=2 ){
if( pVTab->pVtab && pMod->iVersion>=2 ){
int (*xMethod)(sqlite3_vtab *, int);
switch( op ){
case SAVEPOINT_BEGIN:
@ -906,7 +906,7 @@ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
rc = xMethod(pVTab->pVtab, iSavepoint);
}
}
}

View File

@ -3167,7 +3167,7 @@ static void bestBtreeIndex(
** slower with larger records, presumably because fewer records fit
** on one page and hence more pages have to be fetched.
**
** The ANALYZE command and the sqlite_stat1 and sqlite_stat2 tables do
** The ANALYZE command and the sqlite_stat1 and sqlite_stat3 tables do
** not give us data on the relative sizes of table and index records.
** So this computation assumes table records are about twice as big
** as index records

View File

@ -846,7 +846,6 @@ do_test alter-14.2 {
set system_table_list {1 sqlite_master}
catchsql ANALYZE
ifcapable analyze { lappend system_table_list 2 sqlite_stat1 }
ifcapable stat2 { lappend system_table_list 3 sqlite_stat2 }
ifcapable stat3 { lappend system_table_list 4 sqlite_stat3 }
foreach {tn tbl} $system_table_list {

View File

@ -1,554 +0,0 @@
# 2009 August 06
#
# 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. This file
# implements tests for the extra functionality provided by the ANALYZE
# command when the library is compiled with SQLITE_ENABLE_STAT2 defined.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !stat2 {
finish_test
return
}
set testprefix analyze2
# Do not use a codec for tests in this file, as the database file is
# manipulated directly using tcl scripts (using the [hexio_write] command).
#
do_not_use_codec
#--------------------------------------------------------------------
# Test organization:
#
# analyze2-1.*: Tests to verify that ANALYZE creates and populates the
# sqlite_stat2 table as expected.
#
# analyze2-2.*: Test that when a table has two indexes on it and either
# index may be used for the scan, the index suggested by
# the contents of sqlite_stat2 table is prefered.
#
# analyze2-3.*: Similar to the previous block of tests, but using tables
# that contain a mixture of NULL, numeric, text and blob
# values.
#
# analyze2-4.*: Check that when an indexed column uses a collation other
# than BINARY, the collation is taken into account when
# using the contents of sqlite_stat2 to estimate the cost
# of a range scan.
#
# analyze2-5.*: Check that collation sequences are used as described above
# even when the only available version of the collation
# function require UTF-16 encoded arguments.
#
# analyze2-6.*: Check that the library behaves correctly when one of the
# sqlite_stat2 or sqlite_stat1 tables are missing.
#
# analyze2-7.*: Check that in a shared-schema situation, nothing goes
# wrong if sqlite_stat2 data is read by one connection,
# and freed by another.
#
proc eqp {sql {db db}} {
uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db
}
do_test analyze2-1.1 {
execsql { CREATE TABLE t1(x PRIMARY KEY) }
for {set i 0} {$i < 1000} {incr i} {
execsql { INSERT INTO t1 VALUES($i) }
}
execsql {
ANALYZE;
SELECT * FROM sqlite_stat2;
}
} [list t1 sqlite_autoindex_t1_1 0 50 \
t1 sqlite_autoindex_t1_1 1 149 \
t1 sqlite_autoindex_t1_1 2 249 \
t1 sqlite_autoindex_t1_1 3 349 \
t1 sqlite_autoindex_t1_1 4 449 \
t1 sqlite_autoindex_t1_1 5 549 \
t1 sqlite_autoindex_t1_1 6 649 \
t1 sqlite_autoindex_t1_1 7 749 \
t1 sqlite_autoindex_t1_1 8 849 \
t1 sqlite_autoindex_t1_1 9 949 \
]
do_test analyze2-1.2 {
execsql {
DELETE FROM t1 WHERe x>9;
ANALYZE;
SELECT tbl, idx, group_concat(sample, ' ') FROM sqlite_stat2;
}
} {t1 sqlite_autoindex_t1_1 {0 1 2 3 4 5 6 7 8 9}}
do_test analyze2-1.3 {
execsql {
DELETE FROM t1 WHERE x>8;
ANALYZE;
SELECT * FROM sqlite_stat2;
}
} {}
do_test analyze2-1.4 {
execsql {
DELETE FROM t1;
ANALYZE;
SELECT * FROM sqlite_stat2;
}
} {}
do_test analyze2-2.1 {
execsql {
BEGIN;
DROP TABLE t1;
CREATE TABLE t1(x, y);
CREATE INDEX t1_x ON t1(x);
CREATE INDEX t1_y ON t1(y);
}
for {set i 0} {$i < 1000} {incr i} {
execsql { INSERT INTO t1 VALUES($i, $i) }
}
execsql COMMIT
execsql ANALYZE
} {}
do_eqp_test 2.2 {
SELECT * FROM t1 WHERE x>500 AND y>700
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
}
do_eqp_test 2.3 {
SELECT * FROM t1 WHERE x>700 AND y>500
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
}
do_eqp_test 2.3 {
SELECT * FROM t1 WHERE y>700 AND x>500
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~100 rows)}
}
do_eqp_test 2.4 {
SELECT * FROM t1 WHERE y>500 AND x>700
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>?) (~100 rows)}
}
do_eqp_test 2.5 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 200 AND y BETWEEN 400 AND 700
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~25 rows)}
}
do_eqp_test 2.6 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 400 AND 700
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~75 rows)}
}
do_eqp_test 2.7 {
SELECT * FROM t1 WHERE x BETWEEN -400 AND -300 AND y BETWEEN 100 AND 300
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
}
do_eqp_test 2.8 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN -400 AND -300
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
}
do_eqp_test 2.9 {
SELECT * FROM t1 WHERE x BETWEEN 500 AND 100 AND y BETWEEN 100 AND 300
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~12 rows)}
}
do_eqp_test 2.10 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 300 AND y BETWEEN 500 AND 100
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~12 rows)}
}
do_test analyze2-3.1 {
set alphabet [list a b c d e f g h i j]
execsql BEGIN
for {set i 0} {$i < 1000} {incr i} {
set str [lindex $alphabet [expr ($i/100)%10]]
append str [lindex $alphabet [expr ($i/ 10)%10]]
append str [lindex $alphabet [expr ($i/ 1)%10]]
execsql { INSERT INTO t1 VALUES($str, $str) }
}
execsql COMMIT
execsql ANALYZE
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE idx = 't1_x'
GROUP BY tbl,idx
}
} {t1 t1_x {100 299 499 699 899 ajj cjj ejj gjj ijj}}
do_test analyze2-3.2 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE idx = 't1_y'
GROUP BY tbl,idx
}
} {t1 t1_y {100 299 499 699 899 ajj cjj ejj gjj ijj}}
do_eqp_test 3.3 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 500 AND y BETWEEN 'a' AND 'b'
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>? AND y<?) (~50 rows)}
}
do_eqp_test 3.4 {
SELECT * FROM t1 WHERE x BETWEEN 100 AND 400 AND y BETWEEN 'a' AND 'h'
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x>? AND x<?) (~100 rows)}
}
do_eqp_test 3.5 {
SELECT * FROM t1 WHERE x<'a' AND y>'h'
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
}
do_eqp_test 3.6 {
SELECT * FROM t1 WHERE x<444 AND y>'h'
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_y (y>?) (~66 rows)}
}
do_eqp_test 3.7 {
SELECT * FROM t1 WHERE x<221 AND y>'g'
} {
0 0 0 {SEARCH TABLE t1 USING INDEX t1_x (x<?) (~66 rows)}
}
do_test analyze2-4.1 {
execsql { CREATE TABLE t3(a COLLATE nocase, b) }
execsql { CREATE INDEX t3a ON t3(a) }
execsql { CREATE INDEX t3b ON t3(b) }
set alphabet [list A b C d E f G h I j]
execsql BEGIN
for {set i 0} {$i < 1000} {incr i} {
set str [lindex $alphabet [expr ($i/100)%10]]
append str [lindex $alphabet [expr ($i/ 10)%10]]
append str [lindex $alphabet [expr ($i/ 1)%10]]
execsql { INSERT INTO t3 VALUES($str, $str) }
}
execsql COMMIT
execsql ANALYZE
} {}
do_test analyze2-4.2 {
execsql {
PRAGMA automatic_index=OFF;
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE idx = 't3a'
GROUP BY tbl,idx;
PRAGMA automatic_index=ON;
}
} {t3 t3a {AfA bEj CEj dEj EEj fEj GEj hEj IEj jEj}}
do_test analyze2-4.3 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE idx = 't3b'
GROUP BY tbl,idx
}
} {t3 t3b {AbA CIj EIj GIj IIj bIj dIj fIj hIj jIj}}
do_eqp_test 4.4 {
SELECT * FROM t3 WHERE a > 'A' AND a < 'C' AND b > 'A' AND b < 'C'
} {
0 0 0 {SEARCH TABLE t3 USING INDEX t3b (b>? AND b<?) (~11 rows)}
}
do_eqp_test 4.5 {
SELECT * FROM t3 WHERE a > 'A' AND a < 'c' AND b > 'A' AND b < 'c'
} {
0 0 0 {SEARCH TABLE t3 USING INDEX t3a (a>? AND a<?) (~22 rows)}
}
ifcapable utf16 {
proc test_collate {enc lhs rhs} {
# puts $enc
return [string compare $lhs $rhs]
}
do_test analyze2-5.1 {
add_test_collate db 0 0 1
execsql { CREATE TABLE t4(x COLLATE test_collate) }
execsql { CREATE INDEX t4x ON t4(x) }
set alphabet [list a b c d e f g h i j]
execsql BEGIN
for {set i 0} {$i < 1000} {incr i} {
set str [lindex $alphabet [expr ($i/100)%10]]
append str [lindex $alphabet [expr ($i/ 10)%10]]
append str [lindex $alphabet [expr ($i/ 1)%10]]
execsql { INSERT INTO t4 VALUES($str) }
}
execsql COMMIT
execsql ANALYZE
} {}
do_test analyze2-5.2 {
execsql {
SELECT tbl,idx,group_concat(sample,' ')
FROM sqlite_stat2
WHERE tbl = 't4'
GROUP BY tbl,idx
}
} {t4 t4x {afa bej cej dej eej fej gej hej iej jej}}
do_eqp_test 5.3 {
SELECT * FROM t4 WHERE x>'ccc'
} {0 0 0 {SEARCH TABLE t4 USING COVERING INDEX t4x (x>?) (~800 rows)}}
do_eqp_test 5.4 {
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ccc' AND t42.x>'ggg'
} {
0 0 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~300 rows)}
0 1 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~800 rows)}
}
do_eqp_test 5.5 {
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'
} {
0 0 0 {SEARCH TABLE t4 AS t41 USING COVERING INDEX t4x (x>?) (~700 rows)}
0 1 1 {SEARCH TABLE t4 AS t42 USING COVERING INDEX t4x (x>?) (~800 rows)}
}
}
#--------------------------------------------------------------------
# These tests, analyze2-6.*, verify that the library behaves correctly
# when one of the sqlite_stat1 and sqlite_stat2 tables is missing.
#
# If the sqlite_stat1 table is not present, then the sqlite_stat2
# table is not read. However, if it is the sqlite_stat2 table that
# is missing, the data in the sqlite_stat1 table is still used.
#
# Tests analyze2-6.1.* test the libary when the sqlite_stat2 table
# is missing. Tests analyze2-6.2.* test the library when sqlite_stat1
# is not present.
#
do_test analyze2-6.0 {
execsql {
DROP TABLE IF EXISTS t4;
CREATE TABLE t5(a, b); CREATE INDEX t5i ON t5(a, b);
CREATE TABLE t6(a, b); CREATE INDEX t6i ON t6(a, b);
}
for {set ii 0} {$ii < 20} {incr ii} {
execsql {
INSERT INTO t5 VALUES($ii, $ii);
INSERT INTO t6 VALUES($ii/10, $ii/10);
}
}
execsql {
CREATE TABLE master AS
SELECT * FROM sqlite_master WHERE name LIKE 'sqlite_stat%'
}
} {}
do_test analyze2-6.1.1 {
eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.2 {
db cache flush
execsql ANALYZE
eqp {SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.4 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.5 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a=? AND b=?) (~9 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.1.6 {
execsql {
PRAGMA writable_schema = 1;
INSERT INTO sqlite_master SELECT * FROM master;
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a = 1 AND
t6.a = 1 AND t6.b = 1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a=?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.1 {
execsql {
DELETE FROM sqlite_stat1;
DELETE FROM sqlite_stat2;
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.2 {
db cache flush
execsql ANALYZE
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.3 {
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.4 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat1';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.5 {
execsql {
PRAGMA writable_schema = 1;
DELETE FROM sqlite_master WHERE tbl_name = 'sqlite_stat2';
}
sqlite3 db test.db
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~60000 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-6.2.6 {
execsql {
PRAGMA writable_schema = 1;
INSERT INTO sqlite_master SELECT * FROM master;
}
sqlite3 db test.db
execsql ANALYZE
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
}
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
#--------------------------------------------------------------------
# These tests, analyze2-7.*, test that the sqlite_stat2 functionality
# works in shared-cache mode. Note that these tests reuse the database
# created for the analyze2-6.* tests.
#
ifcapable shared_cache {
db close
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
proc incr_schema_cookie {zDb} {
foreach iOffset {24 40} {
set cookie [hexio_get_int [hexio_read $zDb $iOffset 4]]
incr cookie
hexio_write $zDb $iOffset [hexio_render_int32 $cookie]
}
}
do_test analyze2-7.1 {
sqlite3 db1 test.db
sqlite3 db2 test.db
db1 cache size 0
db2 cache size 0
execsql { SELECT count(*) FROM t5 } db1
} {20}
do_test analyze2-7.2 {
incr_schema_cookie test.db
execsql { SELECT count(*) FROM t5 } db2
} {20}
do_test analyze2-7.3 {
incr_schema_cookie test.db
execsql { SELECT count(*) FROM t5 } db1
} {20}
do_test analyze2-7.4 {
incr_schema_cookie test.db
execsql { SELECT count(*) FROM t5 } db2
} {20}
do_test analyze2-7.5 {
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.6 {
incr_schema_cookie test.db
execsql { SELECT * FROM sqlite_master } db2
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db2
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.7 {
incr_schema_cookie test.db
execsql { SELECT * FROM sqlite_master } db1
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.8 {
execsql { DELETE FROM sqlite_stat2 } db2
execsql { SELECT * FROM sqlite_master } db1
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.9 {
execsql { SELECT * FROM sqlite_master } db2
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db2
} {0 0 1 {SEARCH TABLE t6 USING COVERING INDEX t6i (a>?) (~1 rows)} 0 1 0 {SEARCH TABLE t5 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
do_test analyze2-7.10 {
incr_schema_cookie test.db
execsql { SELECT * FROM sqlite_master } db1
eqp { SELECT * FROM t5,t6 WHERE t5.rowid=t6.rowid AND
t5.a>1 AND t5.a<15 AND
t6.a>1
} db1
} {0 0 0 {SEARCH TABLE t5 USING COVERING INDEX t5i (a>? AND a<?) (~1 rows)} 0 1 1 {SEARCH TABLE t6 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}}
db1 close
db2 close
sqlite3_enable_shared_cache $::enable_shared_cache
}
finish_test

View File

@ -70,7 +70,7 @@ proc sf_execsql {sql {db db}} {
# Show that there are two possible plans for querying the table with
# a range constraint on the indexed column - "full table scan" or "use
# the index". When the range is specified using literal values, SQLite
# is able to pick the best plan based on the samples in sqlite_stat2.
# is able to pick the best plan based on the samples in sqlite_stat3.
#
# analyze3-1.1.4 - 3.1.9
# Show that using SQL variables produces the same results as using

View File

@ -2321,14 +2321,10 @@ ifcapable compound&&subquery {
}
}
}
ifcapable stat2 {
set stat2 "sqlite_stat2 "
ifcapable stat3 {
set stat3 "sqlite_stat3 "
} else {
ifcapable stat3 {
set stat2 "sqlite_stat3 "
} else {
set stat2 ""
}
set stat3 ""
}
do_test auth-5.2 {
execsql {
@ -2337,7 +2333,7 @@ ifcapable compound&&subquery {
WHERE type='table'
ORDER BY name
}
} "sqlite_stat1 ${stat2}t1 t2 t3 t4"
} "sqlite_stat1 ${stat3}t1 t2 t3 t4"
}
# Ticket #3944

116
test/errmsg.test Normal file
View File

@ -0,0 +1,116 @@
# 2001 September 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# Test that if sqlite3_prepare_v2() is used to prepare a query, the
# error-message associated with an sqlite3_step() error is available
# immediately. Whereas if sqlite3_prepare() is used, it is not available
# until sqlite3_finalize() or sqlite3_reset() has been called.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix errmsg
# Test organization:
#
# errmsg-1.* User-defined SQL function errors
# errmsg-2.* Errors generated by the VDBE (constraint failures etc.)
# errmsg-3.* SQLITE_SCHEMA and statement recompilation errors.
#
proc error_messages_worker {prepare sql schema} {
set ret [list]
set stmt [$prepare db $sql -1 dummy]
execsql $schema
lappend ret [sqlite3_step $stmt]
lappend ret [sqlite3_errmsg db]
lappend ret [sqlite3_finalize $stmt]
lappend ret [sqlite3_errmsg db]
set ret
}
proc error_messages_v2 {sql {schema {}}} {
error_messages_worker sqlite3_prepare_v2 $sql $schema
}
proc error_messages {sql {schema {}}} {
error_messages_worker sqlite3_prepare $sql $schema
}
proc sql_error {msg} { error $msg }
db func sql_error sql_error
#-------------------------------------------------------------------------
# Test error messages returned by user-defined SQL functions.
#
do_test 1.1 {
error_messages "SELECT sql_error('custom message')"
} [list {*}{
SQLITE_ERROR {SQL logic error or missing database}
SQLITE_ERROR {custom message}
}]
do_test 1.2 {
error_messages_v2 "SELECT sql_error('custom message')"
} [list {*}{
SQLITE_ERROR {custom message}
SQLITE_ERROR {custom message}
}]
#-------------------------------------------------------------------------
# Test error messages generated directly by VDBE code (e.g. constraint
# failures).
#
do_execsql_test 2.1 {
CREATE TABLE t1(a PRIMARY KEY, b UNIQUE);
INSERT INTO t1 VALUES('abc', 'def');
}
do_test 2.2 {
error_messages "INSERT INTO t1 VALUES('ghi', 'def')"
} [list {*}{
SQLITE_ERROR {SQL logic error or missing database}
SQLITE_CONSTRAINT {column b is not unique}
}]
do_test 2.3 {
error_messages_v2 "INSERT INTO t1 VALUES('ghi', 'def')"
} [list {*}{
SQLITE_CONSTRAINT {column b is not unique}
SQLITE_CONSTRAINT {column b is not unique}
}]
#-------------------------------------------------------------------------
# Test SQLITE_SCHEMA errors. And, for _v2(), test that if the schema
# change invalidates the SQL statement itself the error message is returned
# correctly.
#
do_execsql_test 3.1.1 {
CREATE TABLE t2(a PRIMARY KEY, b UNIQUE);
INSERT INTO t2 VALUES('abc', 'def');
}
do_test 3.1.2 {
error_messages "SELECT a FROM t2" "DROP TABLE t2"
} [list {*}{
SQLITE_ERROR {SQL logic error or missing database}
SQLITE_SCHEMA {database schema has changed}
}]
do_execsql_test 3.2.1 {
CREATE TABLE t2(a PRIMARY KEY, b UNIQUE);
INSERT INTO t2 VALUES('abc', 'def');
}
do_test 3.2.2 {
error_messages_v2 "SELECT a FROM t2" "DROP TABLE t2"
} [list {*}{
SQLITE_ERROR {no such table: t2}
SQLITE_ERROR {no such table: t2}
}]
finish_test

View File

@ -68,7 +68,7 @@ proc catch_fk_error {zSql} {
if {[string match {*foreign key*} $msg]} {
return ""
}
if {$msg eq "out of memory"} {
if {$msg eq "out of memory" || $msg eq "constraint failed"} {
error 1
}
error $msg

61
test/fts3drop.test Normal file
View File

@ -0,0 +1,61 @@
# 2011 October 29
#
# 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 script is testing the FTS3 module. More specifically,
# that DROP TABLE commands can co-exist with savepoints inside transactions.
# See ticket [48f299634a] for details.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix fts3drop
# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
finish_test
return
}
do_execsql_test 1.1 {
CREATE VIRTUAL TABLE f1 USING fts3;
INSERT INTO f1 VALUES('a b c');
}
do_execsql_test 1.2 {
BEGIN;
INSERT INTO f1 VALUES('d e f');
SAVEPOINT one;
INSERT INTO f1 VALUES('g h i');
DROP TABLE f1;
ROLLBACK TO one;
COMMIT;
}
do_execsql_test 1.3 {
SELECT * FROM f1;
} {{a b c} {d e f}}
do_execsql_test 1.4 {
BEGIN;
INSERT INTO f1 VALUES('g h i');
SAVEPOINT one;
INSERT INTO f1 VALUES('j k l');
DROP TABLE f1;
RELEASE one;
ROLLBACK;
}
do_execsql_test 1.5 {
SELECT * FROM f1;
} {{a b c} {d e f}}
finish_test

View File

@ -18,8 +18,6 @@ set ::testprefix fts3fault
# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }
if 1 {
# Test error handling in the sqlite3Fts3Init() function. This is the
# function that registers the FTS3 module and various support functions
# with SQLite.
@ -146,7 +144,8 @@ do_faultsim_test 7.2 -prep {
execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchinfo=fs3) }
} -test {
faultsim_test_result {1 {unrecognized matchinfo: fs3}} \
{1 {vtable constructor failed: t1}}
{1 {vtable constructor failed: t1}} \
{1 {SQL logic error or missing database}}
}
do_faultsim_test 7.3 -prep {
faultsim_delete_and_reopen
@ -154,9 +153,8 @@ do_faultsim_test 7.3 -prep {
execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchnfo=fts3) }
} -test {
faultsim_test_result {1 {unrecognized parameter: matchnfo=fts3}} \
{1 {vtable constructor failed: t1}}
}
{1 {vtable constructor failed: t1}} \
{1 {SQL logic error or missing database}}
}
proc mit {blob} {

View File

@ -38,6 +38,10 @@ ifcapable !fts3 {
#
# 6.* - Test the effects of messing with the schema of table xxx after
# creating a content=xxx FTS index.
#
# 7.* - Test that if content=xxx is specified and table xxx does not
# exist, the FTS table can still be used for INSERT and some
# SELECT statements.
#
do_execsql_test 1.1.1 {
@ -475,4 +479,23 @@ do_execsql_test 7.1.2 {
SELECT docid FROM ft8 WHERE ft8 MATCH 'N';
} {13 15}
do_execsql_test 7.2.1 {
CREATE VIRTUAL TABLE ft9 USING fts4(content=, x);
INSERT INTO ft9(docid, x) VALUES(13, 'U O N X G');
INSERT INTO ft9(docid, x) VALUES(14, 'C J J U B');
INSERT INTO ft9(docid, x) VALUES(15, 'N J Y G X');
INSERT INTO ft9(docid, x) VALUES(16, 'R Y D O R');
INSERT INTO ft9(docid, x) VALUES(17, 'I Y T Q O');
}
do_execsql_test 7.2.2 {
SELECT docid FROM ft9 WHERE ft9 MATCH 'N';
} {13 15}
do_execsql_test 7.2.3 {
SELECT name FROM sqlite_master WHERE name LIKE 'ft9_%';
} {ft9_segments ft9_segdir ft9_docsize ft9_stat}
do_catchsql_test 7.2.4 {
SELECT * FROM ft9 WHERE ft9 MATCH 'N';
} {1 {SQL logic error or missing database}}
finish_test

View File

@ -867,32 +867,6 @@ if {[db eval {PRAGMA locking_mode}]!="exclusive"} {
catch { db2 close }
}
ifcapable stat2&&utf16 {
do_malloc_test 38 -tclprep {
add_test_collate db 0 0 1
execsql {
ANALYZE;
CREATE TABLE t4(x COLLATE test_collate);
CREATE INDEX t4x ON t4(x);
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 0, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 1, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 2, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 3, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 4, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 5, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 6, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 7, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 8, 'aaa');
INSERT INTO sqlite_stat2 VALUES('t4', 't4x', 9, 'aaa');
}
db close
sqlite3 db test.db
sqlite3_db_config_lookaside db 0 0 0
add_test_collate db 0 0 1
} -sqlbody {
SELECT * FROM t4 AS t41, t4 AS t42 WHERE t41.x>'ddd' AND t42.x>'ccc'
}
}
# Test that if an OOM error occurs, aux-data is still correctly destroyed.
# This test case was causing either a memory-leak or an assert() failure

View File

@ -1178,5 +1178,20 @@ do_test vtab1-17.1 {
catchsql { CREATE VIRTUAL TABLE t4 USING echo(t3); }
} {1 {vtable constructor failed: t4}}
# This test verifies that ticket 48f29963 is fixed.
#
do_test vtab1-17.1 {
execsql {
CREATE TABLE t5(a, b);
CREATE VIRTUAL TABLE e5 USING echo_v2(t5);
BEGIN;
INSERT INTO e5 VALUES(1, 2);
DROP TABLE e5;
SAVEPOINT one;
ROLLBACK TO one;
COMMIT;
}
} {}
unset -nocomplain echo_module_begin_fail
finish_test