Merge in all changes found in the version 3.7.9 release candidate.
FossilOrigin-Name: 23580718e1c15ddb89682d0e7566da4d7276bfe9
This commit is contained in:
commit
f004e1d69e
178
ext/fts3/README.content
Normal file
178
ext/fts3/README.content
Normal 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.
|
||||
|
||||
|
58
manifest
58
manifest
@ -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
|
||||
|
@ -1 +1 @@
|
||||
8baef58170ff851d0c4387a6888f59b487b4f33c
|
||||
23580718e1c15ddb89682d0e7566da4d7276bfe9
|
@ -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.
|
||||
*/
|
||||
|
15
src/build.c
15
src/build.c
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
52
src/test8.c
52
src/test8.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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
116
test/errmsg.test
Normal 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
|
@ -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
61
test/fts3drop.test
Normal 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
|
@ -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} {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user