Compare commits

...

61 Commits

Author SHA1 Message Date
drh 00583291bd Version 3.24.0
FossilOrigin-Name: c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca
2018-06-04 19:24:41 +00:00
drh eb7df46e32 Avoid using a misaligned pointer.
FossilOrigin-Name: 1ecb3aa13de5c8dc611b814ff34010de0bd90aae73d88aa37a59c4627be4cc2d
2018-06-02 19:14:58 +00:00
drh 1fb7a60ca0 Fix the usage of posix_fallocate() so that it correctly responds to
EINVAL returns.

FossilOrigin-Name: ce2c3e7a875ede4366c48660ae8239d2b74e5f690ad5059844a45f1164f41e61
2018-06-02 19:01:54 +00:00
dan 69a4b383a2 Update a test case in malloc5.test to take into account that malloc()
sometimes returns slightly more space than requested.

FossilOrigin-Name: 3d5eae1c26353cdee89f31f1293b05c0edb494c775ba0912d9b4fda9ab0ef304
2018-06-02 17:00:57 +00:00
drh 5ba5f5b5d2 Work around a sanitizer warning about a pointer being only 4-byte aligned
instead of 8-byte aligned.

FossilOrigin-Name: 1b807b51cdf455b4f54216b73fd22bbc90f94e24222401e045f88cfd27f487e3
2018-06-02 16:32:04 +00:00
drh 789df14b11 Proposed fix for the use of posix_fallocate() so that it handles EINVAL
returns correctly.

FossilOrigin-Name: ab3a5539db82814cafb832cdaebd1e14566139306453ef9cdba6b244a994fe0b
2018-06-02 14:37:39 +00:00
drh e893e2e4ee Fix the CSV extension so that it works with single-column CSV files.
FossilOrigin-Name: e336cf00486bdc0ec04ecded2b7c874d73a87e6aba3544e3678bedfb9a4af3b6
2018-06-02 12:05:18 +00:00
drh 4344dbd3ab Ensure that sqlite3AuthRead() is only call for TK_COLUMN and TK_TRIGGER
expression nodes.  This fixes a harmless assert() identified by OSSFuzz.
Move the assert() into a position where it is tested even if the authorizer
is disabled.

FossilOrigin-Name: d0c3beef7cdc680c0768ddd18f766a4ca7be822c1eb1776b2f73b7433d9962dc
2018-06-02 11:31:15 +00:00
dan 0f86c9d8fa Fix a bug in the SQLITE_ENABLE_SORTER_REFERENCES code causing an out-of-bounds
array reference.

FossilOrigin-Name: 8cadaf587dc96370f9c8a1dccc366b93021e8cfe4526da9368a088828fd14faf
2018-06-01 13:30:45 +00:00
drh 416a801600 More documentation typo fixes. No code changes.
FossilOrigin-Name: 66c24513c2f6de98bd888c3e4c07bbb39fabf30ea9dd01eb255460054055347d
2018-05-31 19:14:52 +00:00
drh 8cdafc384e Fix a harmless typo in a comment used to generate documentation.
FossilOrigin-Name: 5a2a88cb01ef4b299f9a5b2963f392a3bae90e8a7f84b190e67f86090f891e23
2018-05-31 19:00:20 +00:00
drh fc232d6f65 Add the Makefile.fallback makefile to the amalgamation tarball.
FossilOrigin-Name: ce3d04563337c9556d66e55acfb454789b0baa49a1be8fcc349251ce88236d62
2018-05-30 14:17:09 +00:00
drh 5d3112872d Do not use the codec on the resetdb.test script.
FossilOrigin-Name: fe55cea0c80ab29120574c5c4a8473b83fc80f79d7e11bc7c326bfdb32aa3902
2018-05-30 07:36:55 +00:00
drh 8e02a180b9 Fix a typo in an error message in the CLI.
FossilOrigin-Name: 808839808141493c1e5122f40b2cdff725be0cd1212e03d609345dbff7af03e4
2018-05-30 07:24:41 +00:00
drh 6a8b94e266 Fix the parser so that it builds with -DSQLITE_OMIT_CTE.
FossilOrigin-Name: 86ee267ee86f5264774a9f215b1158aeaa2d605e77c205731b5ee3945d7de4c2
2018-05-30 01:14:20 +00:00
drh 3e62ddbf13 Fix a harmless compiler warning.
FossilOrigin-Name: 8d02c7a6a09f7520ad180b0d943db475894cd39b0ccdb2ad2c44009d5f25c8a6
2018-05-30 00:59:09 +00:00
dan ea93e2804d Increase the number of database handles opened by test script oserror.test to
provoke an "out of file-descriptors" error to 20000 (from 2000).

FossilOrigin-Name: 3b00f73456c65dfc1827fdada9afb49245f9addfa684d5ae35e69a07f39164bf
2018-05-29 19:12:58 +00:00
dan 867e6de4d7 Fix autoinc.test and resetdb.test so that they work with all permutations.
FossilOrigin-Name: 89f56d6b0a6847b042a1556cdf79c598c9bfdbdd5f9529d508ca7b4d26a6ed38
2018-05-29 16:37:12 +00:00
drh 59ee43a78e Add a comment to justify a goto statement. No code changes.
FossilOrigin-Name: f141d806476aabe592a15d83b72c9409d2cd6bd7f9cced1ea2513c134191430a
2018-05-29 15:18:31 +00:00
dan 1d40cdbd4b More minor changes to test scripts.
FossilOrigin-Name: ce9b756f09df4feb485bbf9695f8c6774906eb1b2fb45a340b74ffd21c9adfd8
2018-05-29 14:29:28 +00:00
dan d3e17ffbb7 Fix some test script issues caused by recent EXPLAIN QUERY PLAN enhancements.
FossilOrigin-Name: f808e22831c33bfe3d0dd44e209f64d527c23ca7c72be7c694736535afee1317
2018-05-29 14:06:55 +00:00
dan 66e82b47d9 Do not run test file "resetdb.test" as part of permutation "inmemory_journal".
FossilOrigin-Name: 4921e5bae4c12c3413cc0b2e58766cf2ac117ad95f92fcd1c2457db6cfabb054
2018-05-29 13:25:14 +00:00
dan fecfb3189b Do not require a statement journal in cases where REPLACE conflict handling is
used to insert a single row, so long as the REPLACE operation cannot fire any
triggers or foreign key actions.

FossilOrigin-Name: 469a62ca33081854e54f3af6d93ab5a350484b149c8c8c4ee8be0ae5418382d9
2018-05-28 18:29:46 +00:00
drh 50baf3d525 When compiling with SQLITE_DEBUG, add run-time checks to ensure that no statement aborts unless either there have been no writes or else there is a statement journal.
FossilOrigin-Name: ce99c7724460b9cf4ccaf7f6bc1a522b5c34d5ad0683d465f7926b10f31f7d05
2018-05-28 18:25:19 +00:00
drh 341141c339 Fix the build so that it works with -DSQLITE_TEST_REALLOC_STRESS
FossilOrigin-Name: 90ba2b2e5ce2619e68879eb325b43639159f27eb462b9fb6795534c91200a3d2
2018-05-28 17:43:28 +00:00
drh 4031bafafb When compiling with SQLITE_DEBUG, add run-time checks to ensure that no
statement aborts unless either there have been no writes or else there is
a statement journal.

FossilOrigin-Name: 5a4542dbcf17a9f7fed600897555c271e1651fd50eb41d0b126725b486e1d14c
2018-05-28 17:31:20 +00:00
drh 9201184711 Store application-defined function names as lower-case to avoid the need
for case conversions before calling xFindFunction on virtual tables.
Avoid using lookaside to store the destructors for application defined
functions, as lookaside should be reserved for transient allocations.

FossilOrigin-Name: 777189ce88799f93f393fd14fd716111c85bcdcb23690fd561f78ea2bd2ce5da
2018-05-26 16:00:26 +00:00
drh 7fc86b96ba Add a single sentence of documentation about the virtual table
scan flags.  No changes to code.

FossilOrigin-Name: 27b4fa5dd0defc6ddaf5d8cde6a1e1162b70d99bfdc69c1d2290621a6d23ed91
2018-05-26 13:55:04 +00:00
drh 338e311acb When doing a one-pass UPDATE or DELETE on virtual tables, close the cursor
prior to running VUpdate.  This allows one-pass to work on virtual tables
that do not allow concurrent reads and writes.  Enhance rtree to take
advantage of this new capability.

FossilOrigin-Name: b816023ce07d01024d5769e16db924374a49bf909edd12dc1344a0a1ef693db5
2018-05-24 23:51:57 +00:00
drh 30fc7f8009 New test case for reading and writing the same rtree concurrently.
FossilOrigin-Name: 3ba08e53d54165f5541756ad13a4c2f0b18516cb612a256e056ed1ff76c1fa83
2018-05-24 22:42:27 +00:00
drh c8c9cdd9dd Do not allow RTree writes when a read cursor is active on the same virtual
table, as the writes might rebalance and disrupt the read cursors.  Return
the new SQLITE_LOCKED_VTAB error code if this happens.

FossilOrigin-Name: d4ce66610851c825cb712f985216b63e015c753fdd5521f929c67ad18bfd7664
2018-05-24 22:31:01 +00:00
drh b9cd2c4536 In the OOM testing logic, add the sqlite3FirstFault() routine as a place to
set a breakpoint the first time any simulated OOM fault occurs for a single
test case.

FossilOrigin-Name: b4d80bd287ca7f3a6d182ba2435273266035b94fdf6a44047a64a4eff931c571
2018-05-24 17:38:00 +00:00
drh bbd574bc37 Fix a typo in a comment used to generate VDBE opcode documentation. No
code changes.

FossilOrigin-Name: 36cdfbf2ce1811691c790fde3eaeed0238c03b4dc97dc3a20d1e0397520145d1
2018-05-24 17:25:35 +00:00
drh cf8784cd8f Addition cases for rtree preformance testing in speedtest1.c. Add the
--nodiff option to the speed-check.sh script.

FossilOrigin-Name: 95f2d62cf3cf8dbe0f12b652b47fe1f8e0f52bc269e269955fafdf802afc47c1
2018-05-24 16:18:35 +00:00
drh 7458a9f3f7 Updates to the sqlite3_vtab_nochange() documentation. No changes to code.
FossilOrigin-Name: 5bd99abc10b8153aadff5f815ae15fbe375f34f043c65def4be03014d2efdb50
2018-05-24 13:59:45 +00:00
drh 4c57e326ef Remove a branch that is no longer used due to the fix to the
sqlite_sequence schema problem, ticket
[d8dc2b3a58cd5dc2918a1d4acbba4676a23ada4c]

FossilOrigin-Name: 066742692a9e8735b814c6a145545f97a7fb10b29cead78e68e25324e79aabaa
2018-05-23 17:53:07 +00:00
drh 186ebd41cf Verify that the sqlite_sequence table exists and is in approximately the
correct format prior to using it to process an autoincrement table.
Fix for ticket [d8dc2b3a58cd5dc2918a1d4a].

FossilOrigin-Name: e199e859ace4f8381c6380175206e7a276e3f2228fadbbca9341bca8d2fc445d
2018-05-23 16:50:21 +00:00
drh e8cf689df3 Add support for auxiliary columns to the rtree extension.
FossilOrigin-Name: c6071ac99cfa4b6272ac4d739fc61a85acb544f6c1c2ae67b31e92aadcc995bd
2018-05-18 17:58:33 +00:00
drh 16d261b3ef Merge enhancements from trunk, especially the CLI fixes.
FossilOrigin-Name: a350040a3bb962823f92908fb31cade52baf13eab90ef608ca3a8349e4c28c9d
2018-05-18 17:17:36 +00:00
drh 9e80403bfc In the CLI, detect and report errors on sqlite3_close(). Clear global
variables prior to exit to so that valgrind can better detect resource
leaks.

FossilOrigin-Name: e3b2e0a078b82ac6cd3c3312e8ac0983c1375e1052f1e324476d2f8d1b227c30
2018-05-18 17:11:50 +00:00
drh a02fd67b99 Avoid unnecessary sqlite3_finalize() operations.
FossilOrigin-Name: 16f71032a3a2919cb226b25b5256a370adb5c55fa506d4774b7f83dc8868e793
2018-05-18 16:53:07 +00:00
drh 136c9903bf Fix a prepare-statement leak.
FossilOrigin-Name: 95fd296ffc8130526a1453cbdca6ce47f22fc5b5c474aa31d66b627d0c7393a1
2018-05-18 16:46:09 +00:00
drh 252f39619a Improved error messages. Limit the number of auxiliary columns to 100.
FossilOrigin-Name: 059d20abd57727e6d312f15b640359ef778786f577d9b50b17b57195db2d0aef
2018-05-18 15:21:43 +00:00
drh bc30e2023b Improvements to integer/float comparisons on architectures that lack a
"long double" type.

FossilOrigin-Name: 5139ea62a8a6c6dc6558c337de39bcbadd26f6515742263387be03c862c78cf0
2018-05-18 14:24:23 +00:00
drh 8d1751b6fa Remove incorrect NEVER() macro added by the previous check-in.
FossilOrigin-Name: 3d6625111319c0356c57aaf7b7460fd882c3f00ca668dc43c0abe3403c7c2ba3
2018-05-18 14:19:35 +00:00
drh 6c319e1238 Improvements to the sqlite3IntFloatCompare() routine for systems that
lack the long double type.

FossilOrigin-Name: ea6a03a89dc23e860e53e79ec3fddf0ae7072a23b73aef3d2d181b426566b677
2018-05-18 13:39:00 +00:00
drh be4ccb2838 In the CLI with the -A command, if the file does not previously exist and
its name looks like a ZIP archive name, then create it as a ZIP archive.

FossilOrigin-Name: 33dc8fad7f2b467f259eb78eb7342a760f01d54d95da7fe4cace10e558788a58
2018-05-17 20:04:24 +00:00
drh d0f9cdcc63 Improved error and help messages for the ".archive" command and "-A" option
to the CLI. If a memory leak in --list processing.

FossilOrigin-Name: 02541ac6f919a8a8b18ef0525c4ee24fdbc5c1883171fb1a492434cd0f006f7c
2018-05-17 14:09:06 +00:00
drh 1f22f62582 Fix memory errors associated with argv in the CLI when it is
compiled on Windows.

FossilOrigin-Name: 4474d69b5c21b4e6f0d1376fbceca0f18c715ff673aea63053a02bfbe041d03b
2018-05-17 13:29:14 +00:00
drh 26fb126622 Fix an issue with rtreecheck() and auxiliary data columns.
FossilOrigin-Name: 46715136078a51ca7dd08b83214d6ad0e85728af8a26cd342077b8dd4ada1d60
2018-05-16 19:56:20 +00:00
drh 7578456c25 Do not allow auxiliary columns in the rtree to interfere with query planning.
Begin adding test cases.

FossilOrigin-Name: 9abe023e1afa7dc1a7eba7fbb3128401de129873d86b7c71c221decca26a821c
2018-05-16 19:07:07 +00:00
drh 1e76c22b4a Fix the OOM issue mentioned in the previous check-in.
FossilOrigin-Name: c489d8e44eac4cd355096ab66bb40f13ef662f31e080c9f1f2ee379fe55b207a
2018-05-16 18:18:24 +00:00
drh e297196524 Initial implementation of the ability to have auxiliary columns in an rtree
virtual table that store arbitrary content.  It mostly works, but there are
some minor issues in OOM corner cases.

FossilOrigin-Name: 0c87fec970221f954e0a92f3ef0437b382255479fac5b403ee37b1bb5ab29719
2018-05-16 17:57:30 +00:00
drh f80bba9d8d Enhance the sqlite3_str_new() interface so that it always returns a valid
and non-NULL pointer even in an OOM condition.

FossilOrigin-Name: ed5b09680fd6659ebbe5ace3c1c56f3962bbd75cfdf65c7565651900cf87917a
2018-05-16 15:35:03 +00:00
drh dd7460f0fd Correct output for the fullkey column of json_each() when the total JSON
input is a simple value, not an array or object.

FossilOrigin-Name: b45b18850c59f22a163ee482f529f578a8798f96d0e26b5a061d336d480a1540
2018-05-16 12:19:11 +00:00
dan a44005af4f Fix a test case problem in wherelimit.test.
FossilOrigin-Name: 3012df8b2c0b19d27260f389147a96c501aee9a4aee3813834cc9e438dbacede
2018-05-15 09:09:00 +00:00
drh 492ad131bd Make more aggressive use of automatic indexes when processing materalized
views and subqueries.

FossilOrigin-Name: 172f5bd27e47cbdaaab54fe4383a5ee505d285257af6153ed626d9493a4adab3
2018-05-14 22:46:11 +00:00
drh a090ab90d6 Convert the schema creation logic in the rtree extension to use the
new sqlite3_str interface.

FossilOrigin-Name: fd8b8c4196d3f0f6cb129f43ebf473ada86eefdf16181fa70ceee21e1232b5e1
2018-05-14 15:26:05 +00:00
mistachkin a3926f4bbf Fix typo in the shell.c source file.
FossilOrigin-Name: 389dc0a901b0ce54c3c773d63e5b288f6dd28b96dffc4b77861db89b275b57d6
2018-05-14 12:23:04 +00:00
drh fc97c1c8cb Export the deduceDatabaseType() function the shell.c source file.
FossilOrigin-Name: d0f35739af3b226c8eef39676407293650cde551acef06fe8628fdd5b59bd66a
2018-05-14 00:41:12 +00:00
drh 69ed38a822 Add the --append option to the ".backup" command in the CLI.
FossilOrigin-Name: 0dfdbdee527b0c429703bc2696bf8d8e44a852aafe0aca742b9d7152eb1f932e
2018-05-14 00:23:08 +00:00
55 changed files with 1245 additions and 366 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_D
include_HEADERS = sqlite3.h sqlite3ext.h
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs
EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/make
#
# If the configure script does not work, then this Makefile is available
# as a backup. Manually configure the variables below.
#
# Note: This makefile works out-of-the-box on MacOS 10.2 (Jaguar)
#
CC = gcc
CFLAGS = -O0 -I.
LIBS = -lz
COPTS += -D_BSD_SOURCE
COPTS += -DSQLITE_ENABLE_LOCKING_STYLE=0
COPTS += -DSQLITE_THREADSAFE=0
COPTS += -DSQLITE_OMIT_LOAD_EXTENSION
COPTS += -DSQLITE_WITHOUT_ZONEMALLOC
COPTS += -DSQLITE_ENABLE_RTREE
sqlite3: shell.c sqlite3.c
$(CC) $(CFLAGS) $(COPTS) -o sqlite3 shell.c sqlite3.c $(LIBS)
-1
View File
@@ -286,7 +286,6 @@ do_setup_rec_test $tn.14 {
INSERT INTO t9 VALUES(?, ?, ?);
} {
CREATE INDEX t10_idx_00000062 ON t10(b);
-- TRIGGER t9t
SEARCH TABLE t10 USING INDEX t10_idx_00000062 (b=?)
}
+3 -1
View File
@@ -1152,7 +1152,9 @@ int idxFindIndexes(
}
}
pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail);
if( zDetail[0]!='-' ){
pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail);
}
}
for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){
+4 -5
View File
@@ -205,7 +205,8 @@ static int csv_append(CsvReader *p, char c){
** + Store the character that terminates the field in p->cTerm. Store
** EOF on end-of-file.
**
** Return "" at EOF. Return 0 on an OOM error.
** Return 0 at EOF or on OOM. On EOF, the p->cTerm character will have
** been set to EOF.
*/
static char *csv_read_one_field(CsvReader *p){
int c;
@@ -213,7 +214,7 @@ static char *csv_read_one_field(CsvReader *p){
c = csv_getc(p);
if( c==EOF ){
p->cTerm = EOF;
return "";
return 0;
}
if( c=='"' ){
int pc, ppc;
@@ -544,8 +545,7 @@ static int csvtabConnect(
pNew->nCol = nCol;
}else{
do{
const char *z = csv_read_one_field(&sRdr);
if( z==0 ) goto csvtab_connect_oom;
csv_read_one_field(&sRdr);
pNew->nCol++;
}while( sRdr.cTerm==',' );
}
@@ -663,7 +663,6 @@ static int csvtabNext(sqlite3_vtab_cursor *cur){
do{
z = csv_read_one_field(&pCur->rdr);
if( z==0 ){
csv_xfer_error(pTab, &pCur->rdr);
break;
}
if( i<pTab->nCol ){
+1 -1
View File
@@ -2118,7 +2118,7 @@ static int jsonEachColumn(
}
if( p->eType==JSON_ARRAY ){
jsonPrintf(30, &x, "[%d]", p->iRowid);
}else{
}else if( p->eType==JSON_OBJECT ){
jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1);
}
}
+244 -88
View File
@@ -24,14 +24,15 @@
**
** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB)
** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
**
** The data for each node of the r-tree structure is stored in the %_node
** table. For each node that is not the root node of the r-tree, there is
** an entry in the %_parent table associating the node with its parent.
** And for each row of data in the table, there is an entry in the %_rowid
** table that maps from the entries rowid to the id of the node that it
** is stored on.
** is stored on. If the r-tree contains auxiliary columns, those are stored
** on the end of the %_rowid table.
**
** The root node of an r-tree always exists, even if the r-tree table is
** empty. The nodeno of the root node is always 1. All other nodes in the
@@ -94,6 +95,9 @@ typedef struct RtreeSearchPoint RtreeSearchPoint;
/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */
#define RTREE_MAX_DIMENSIONS 5
/* Maximum number of auxiliary columns */
#define RTREE_MAX_AUX_COLUMN 100
/* Size of hash table Rtree.aHash. This hash table is not expected to
** ever contain very many entries, so a fixed number of buckets is
** used.
@@ -122,12 +126,15 @@ struct Rtree {
u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */
u8 nBytesPerCell; /* Bytes consumed per cell */
u8 inWrTrans; /* True if inside write transaction */
u8 nAux; /* # of auxiliary columns in %_rowid */
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
char *zName; /* Name of r-tree table */
u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
u32 nCursor; /* Number of open cursors */
u32 nNodeRef; /* Number RtreeNodes with positive nRef */
char *zReadAuxSql; /* SQL for statement to read aux data */
/* List of nodes removed during a CondenseTree operation. List is
** linked together via the pointer normally used for hash chains -
@@ -154,6 +161,9 @@ struct Rtree {
sqlite3_stmt *pWriteParent;
sqlite3_stmt *pDeleteParent;
/* Statement for writing to the "aux:" fields, if there are any */
sqlite3_stmt *pWriteAux;
RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */
};
@@ -230,6 +240,7 @@ struct RtreeCursor {
sqlite3_vtab_cursor base; /* Base class. Must be first */
u8 atEOF; /* True if at end of search */
u8 bPoint; /* True if sPoint is valid */
u8 bAuxValid; /* True if pReadAux is valid */
int iStrategy; /* Copy of idxNum search parameter */
int nConstraint; /* Number of entries in aConstraint */
RtreeConstraint *aConstraint; /* Search constraints. */
@@ -237,6 +248,7 @@ struct RtreeCursor {
int nPoint; /* Number of slots used in aPoint[] */
int mxLevel; /* iLevel value for root of the tree */
RtreeSearchPoint *aPoint; /* Priority queue for search points */
sqlite3_stmt *pReadAux; /* Statement to read aux-data */
RtreeSearchPoint sPoint; /* Cached next search point */
RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */
u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */
@@ -523,6 +535,7 @@ static int writeInt64(u8 *p, i64 i){
*/
static void nodeReference(RtreeNode *p){
if( p ){
assert( p->nRef>0 );
p->nRef++;
}
}
@@ -590,6 +603,7 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
memset(pNode, 0, sizeof(RtreeNode) + pRtree->iNodeSize);
pNode->zData = (u8 *)&pNode[1];
pNode->nRef = 1;
pRtree->nNodeRef++;
pNode->pParent = pParent;
pNode->isDirty = 1;
nodeReference(pParent);
@@ -623,10 +637,10 @@ static int nodeAcquire(
/* Check if the requested node is already in the hash table. If so,
** increase its reference count and return it.
*/
if( (pNode = nodeHashLookup(pRtree, iNode)) ){
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
assert( !pParent || !pNode->pParent || pNode->pParent==pParent );
if( pParent && !pNode->pParent ){
nodeReference(pParent);
pParent->nRef++;
pNode->pParent = pParent;
}
pNode->nRef++;
@@ -665,6 +679,7 @@ static int nodeAcquire(
pNode->pParent = pParent;
pNode->zData = (u8 *)&pNode[1];
pNode->nRef = 1;
pRtree->nNodeRef++;
pNode->iNode = iNode;
pNode->isDirty = 0;
pNode->pNext = 0;
@@ -705,7 +720,10 @@ static int nodeAcquire(
}
*ppNode = pNode;
}else{
sqlite3_free(pNode);
if( pNode ){
pRtree->nNodeRef--;
sqlite3_free(pNode);
}
*ppNode = 0;
}
@@ -802,8 +820,10 @@ static int nodeRelease(Rtree *pRtree, RtreeNode *pNode){
int rc = SQLITE_OK;
if( pNode ){
assert( pNode->nRef>0 );
assert( pRtree->nNodeRef>0 );
pNode->nRef--;
if( pNode->nRef==0 ){
pRtree->nNodeRef--;
if( pNode->iNode==1 ){
pRtree->iDepth = -1;
}
@@ -920,8 +940,9 @@ static void rtreeRelease(Rtree *pRtree){
pRtree->nBusy--;
if( pRtree->nBusy==0 ){
pRtree->inWrTrans = 0;
pRtree->nCursor = 0;
assert( pRtree->nCursor==0 );
nodeBlobReset(pRtree);
assert( pRtree->nNodeRef==0 );
sqlite3_finalize(pRtree->pWriteNode);
sqlite3_finalize(pRtree->pDeleteNode);
sqlite3_finalize(pRtree->pReadRowid);
@@ -930,6 +951,8 @@ static void rtreeRelease(Rtree *pRtree){
sqlite3_finalize(pRtree->pReadParent);
sqlite3_finalize(pRtree->pWriteParent);
sqlite3_finalize(pRtree->pDeleteParent);
sqlite3_finalize(pRtree->pWriteAux);
sqlite3_free(pRtree->zReadAuxSql);
sqlite3_free(pRtree);
}
}
@@ -1018,6 +1041,7 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
RtreeCursor *pCsr = (RtreeCursor *)cur;
assert( pRtree->nCursor>0 );
freeCursorConstraints(pCsr);
sqlite3_finalize(pCsr->pReadAux);
sqlite3_free(pCsr->aPoint);
for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]);
sqlite3_free(pCsr);
@@ -1389,7 +1413,7 @@ static RtreeSearchPoint *rtreeSearchPointNew(
if( ii<RTREE_CACHE_SZ ){
assert( pCur->aNode[ii]==0 );
pCur->aNode[ii] = pCur->aNode[0];
}else{
}else{
nodeRelease(RTREE_OF_CURSOR(pCur), pCur->aNode[0]);
}
pCur->aNode[0] = 0;
@@ -1560,6 +1584,10 @@ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){
/* Move to the next entry that matches the configured constraints. */
RTREE_QUEUE_TRACE(pCsr, "POP-Nx:");
if( pCsr->bAuxValid ){
pCsr->bAuxValid = 0;
sqlite3_reset(pCsr->pReadAux);
}
rtreeSearchPointPop(pCsr);
rc = rtreeStepToLeaf(pCsr);
return rc;
@@ -1594,7 +1622,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
if( p==0 ) return SQLITE_OK;
if( i==0 ){
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else{
}else if( i<=pRtree->nDim2 ){
nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
@@ -1605,7 +1633,27 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
assert( pRtree->eCoordType==RTREE_COORD_INT32 );
sqlite3_result_int(ctx, c.i);
}
}
}else{
if( !pCsr->bAuxValid ){
if( pCsr->pReadAux==0 ){
rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0,
&pCsr->pReadAux, 0);
if( rc ) return rc;
}
sqlite3_bind_int64(pCsr->pReadAux, 1,
nodeGetRowid(pRtree, pNode, p->iCell));
rc = sqlite3_step(pCsr->pReadAux);
if( rc==SQLITE_ROW ){
pCsr->bAuxValid = 1;
}else{
sqlite3_reset(pCsr->pReadAux);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
return rc;
}
}
sqlite3_result_value(ctx,
sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1));
}
return SQLITE_OK;
}
@@ -1683,14 +1731,17 @@ static int rtreeFilter(
int ii;
int rc = SQLITE_OK;
int iCell = 0;
sqlite3_stmt *pStmt;
rtreeReference(pRtree);
/* Reset the cursor to the same state as rtreeOpen() leaves it in. */
freeCursorConstraints(pCsr);
sqlite3_free(pCsr->aPoint);
pStmt = pCsr->pReadAux;
memset(pCsr, 0, sizeof(RtreeCursor));
pCsr->base.pVtab = (sqlite3_vtab*)pRtree;
pCsr->pReadAux = pStmt;
pCsr->iStrategy = idxNum;
if( idxNum==1 ){
@@ -1853,10 +1904,14 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
*/
pIdxInfo->estimatedCost = 30.0;
pIdxInfo->estimatedRows = 1;
pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE;
return SQLITE_OK;
}
if( p->usable && (p->iColumn>0 || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){
if( p->usable
&& ((p->iColumn>0 && p->iColumn<=pRtree->nDim2)
|| p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
){
u8 op;
switch( p->op ){
case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
@@ -2429,7 +2484,7 @@ static int SplitNode(
}else{
pLeft = pNode;
pRight = nodeNew(pRtree, pLeft->pParent);
nodeReference(pLeft);
pLeft->nRef++;
}
if( !pLeft || !pRight ){
@@ -2919,6 +2974,7 @@ static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){
rc = reinsertNodeContent(pRtree, pLeaf);
}
pRtree->pDeleted = pLeaf->pNext;
pRtree->nNodeRef--;
sqlite3_free(pLeaf);
}
@@ -3015,7 +3071,7 @@ static int rtreeConstraintError(Rtree *pRtree, int iCol){
static int rtreeUpdate(
sqlite3_vtab *pVtab,
int nData,
sqlite3_value **azData,
sqlite3_value **aData,
sqlite_int64 *pRowid
){
Rtree *pRtree = (Rtree *)pVtab;
@@ -3023,6 +3079,12 @@ static int rtreeUpdate(
RtreeCell cell; /* New cell to insert if nData>1 */
int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
if( pRtree->nNodeRef ){
/* Unable to write to the btree while another cursor is reading from it,
** since the write might do a rebalance which would disrupt the read
** cursor. */
return SQLITE_LOCKED_VTAB;
}
rtreeReference(pRtree);
assert(nData>=1);
@@ -3041,8 +3103,10 @@ static int rtreeUpdate(
*/
if( nData>1 ){
int ii;
int nn = nData - 4;
/* Populate the cell.aCoord[] array. The first coordinate is azData[3].
if( nn > pRtree->nDim2 ) nn = pRtree->nDim2;
/* Populate the cell.aCoord[] array. The first coordinate is aData[3].
**
** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared
** with "column" that are interpreted as table constraints.
@@ -3050,13 +3114,12 @@ static int rtreeUpdate(
** This problem was discovered after years of use, so we silently ignore
** these kinds of misdeclared tables to avoid breaking any legacy.
*/
assert( nData<=(pRtree->nDim2 + 3) );
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
for(ii=0; ii<nData-4; ii+=2){
cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
for(ii=0; ii<nn; ii+=2){
cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
@@ -3065,9 +3128,9 @@ static int rtreeUpdate(
}else
#endif
{
for(ii=0; ii<nData-4; ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
for(ii=0; ii<nn; ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
@@ -3077,10 +3140,10 @@ static int rtreeUpdate(
/* If a rowid value was supplied, check if it is already present in
** the table. If so, the constraint has failed. */
if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){
cell.iRowid = sqlite3_value_int64(azData[2]);
if( sqlite3_value_type(azData[0])==SQLITE_NULL
|| sqlite3_value_int64(azData[0])!=cell.iRowid
if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
cell.iRowid = sqlite3_value_int64(aData[2]);
if( sqlite3_value_type(aData[0])==SQLITE_NULL
|| sqlite3_value_int64(aData[0])!=cell.iRowid
){
int steprc;
sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
@@ -3099,16 +3162,16 @@ static int rtreeUpdate(
}
}
/* If azData[0] is not an SQL NULL value, it is the rowid of a
/* If aData[0] is not an SQL NULL value, it is the rowid of a
** record to delete from the r-tree table. The following block does
** just that.
*/
if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){
rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0]));
if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){
rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
}
/* If the azData[] array contains more than one element, elements
** (azData[2]..azData[argc-1]) contain a new record to insert into
/* If the aData[] array contains more than one element, elements
** (aData[2]..aData[argc-1]) contain a new record to insert into
** the r-tree structure.
*/
if( rc==SQLITE_OK && nData>1 ){
@@ -3133,6 +3196,16 @@ static int rtreeUpdate(
rc = rc2;
}
}
if( pRtree->nAux ){
sqlite3_stmt *pUp = pRtree->pWriteAux;
int jj;
sqlite3_bind_int64(pUp, 1, *pRowid);
for(jj=0; jj<pRtree->nAux; jj++){
sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
}
sqlite3_step(pUp);
rc = sqlite3_reset(pUp);
}
}
constraint:
@@ -3289,18 +3362,18 @@ static int rtreeSqlInit(
#define N_STATEMENT 8
static const char *azSql[N_STATEMENT] = {
/* Write the xxx_node table */
"INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(:1, :2)",
"DELETE FROM '%q'.'%q_node' WHERE nodeno = :1",
"INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(?1, ?2)",
"DELETE FROM '%q'.'%q_node' WHERE nodeno = ?1",
/* Read and write the xxx_rowid table */
"SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = :1",
"INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(:1, :2)",
"DELETE FROM '%q'.'%q_rowid' WHERE rowid = :1",
"SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = ?1",
"INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(?1, ?2)",
"DELETE FROM '%q'.'%q_rowid' WHERE rowid = ?1",
/* Read and write the xxx_parent table */
"SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = :1",
"INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(:1, :2)",
"DELETE FROM '%q'.'%q_parent' WHERE nodeno = :1"
"SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1",
"INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)",
"DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1"
};
sqlite3_stmt **appStmt[N_STATEMENT];
int i;
@@ -3308,14 +3381,25 @@ static int rtreeSqlInit(
pRtree->db = db;
if( isCreate ){
char *zCreate = sqlite3_mprintf(
"CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY, data BLOB);"
"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY, nodeno INTEGER);"
"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,"
" parentnode INTEGER);"
"INSERT INTO '%q'.'%q_node' VALUES(1, zeroblob(%d))",
zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, zDb, zPrefix, pRtree->iNodeSize
);
char *zCreate;
sqlite3_str *p = sqlite3_str_new(db);
int ii;
sqlite3_str_appendf(p,
"CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno",
zDb, zPrefix);
for(ii=0; ii<pRtree->nAux; ii++){
sqlite3_str_appendf(p,",a%d",ii);
}
sqlite3_str_appendf(p,
");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);",
zDb, zPrefix);
sqlite3_str_appendf(p,
"CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);",
zDb, zPrefix);
sqlite3_str_appendf(p,
"INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))",
zDb, zPrefix, pRtree->iNodeSize);
zCreate = sqlite3_str_finish(p);
if( !zCreate ){
return SQLITE_NOMEM;
}
@@ -3337,7 +3421,17 @@ static int rtreeSqlInit(
rc = rtreeQueryStat1(db, pRtree);
for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){
char *zSql = sqlite3_mprintf(azSql[i], zDb, zPrefix);
char *zSql;
const char *zFormat;
if( i!=3 || pRtree->nAux==0 ){
zFormat = azSql[i];
}else {
/* An UPSERT is very slightly slower than REPLACE, but it is needed
** if there are auxiliary columns */
zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)"
"ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno";
}
zSql = sqlite3_mprintf(zFormat, zDb, zPrefix);
if( zSql ){
rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
appStmt[i], 0);
@@ -3346,6 +3440,32 @@ static int rtreeSqlInit(
}
sqlite3_free(zSql);
}
if( pRtree->nAux ){
pRtree->zReadAuxSql = sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
zDb, zPrefix);
if( pRtree->zReadAuxSql==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_str *p = sqlite3_str_new(db);
int ii;
char *zSql;
sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix);
for(ii=0; ii<pRtree->nAux; ii++){
if( ii ) sqlite3_str_append(p, ",", 1);
sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2);
}
sqlite3_str_appendf(p, " WHERE rowid=?1");
zSql = sqlite3_str_finish(p);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT,
&pRtree->pWriteAux, 0);
sqlite3_free(zSql);
}
}
}
return rc;
}
@@ -3448,17 +3568,22 @@ static int rtreeInit(
int nDb; /* Length of string argv[1] */
int nName; /* Length of string argv[2] */
int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32);
sqlite3_str *pSql;
char *zSql;
int ii = 4;
int iErr;
const char *aErrMsg[] = {
0, /* 0 */
"Wrong number of columns for an rtree table", /* 1 */
"Too few columns for an rtree table", /* 2 */
"Too many columns for an rtree table" /* 3 */
"Too many columns for an rtree table", /* 3 */
"Auxiliary rtree columns must be last" /* 4 */
};
int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2;
if( aErrMsg[iErr] ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */
if( argc>RTREE_MAX_AUX_COLUMN+3 ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
return SQLITE_ERROR;
}
@@ -3476,53 +3601,73 @@ static int rtreeInit(
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
pRtree->nDim = (u8)((argc-4)/2);
pRtree->nDim2 = pRtree->nDim*2;
pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
/* Figure out the node size to use. */
rc = getNodeSize(db, pRtree, isCreate, pzErr);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
if( rc==SQLITE_OK ){
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
pSql = sqlite3_str_new(db);
sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]);
for(ii=4; ii<argc; ii++){
if( argv[ii][0]=='+' ){
pRtree->nAux++;
sqlite3_str_appendf(pSql, ",%s", argv[ii]+1);
}else if( pRtree->nAux>0 ){
break;
}else{
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
char *zTmp;
int ii;
for(ii=4; zSql && ii<argc; ii++){
zTmp = zSql;
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
sqlite3_free(zTmp);
}
if( zSql ){
zTmp = zSql;
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
sqlite3_free(zSql);
pRtree->nDim2++;
sqlite3_str_appendf(pSql, ",%s", argv[ii]);
}
}
if( rc==SQLITE_OK ){
*ppVtab = (sqlite3_vtab *)pRtree;
}else{
assert( *ppVtab==0 );
assert( pRtree->nBusy==1 );
rtreeRelease(pRtree);
sqlite3_str_appendf(pSql, ");");
zSql = sqlite3_str_finish(pSql);
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( ii<argc ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[4]);
rc = SQLITE_ERROR;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
sqlite3_free(zSql);
if( rc ) goto rtreeInit_fail;
pRtree->nDim = pRtree->nDim2/2;
if( pRtree->nDim<1 ){
iErr = 2;
}else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){
iErr = 3;
}else if( pRtree->nDim2 % 2 ){
iErr = 1;
}else{
iErr = 0;
}
if( iErr ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]);
goto rtreeInit_fail;
}
pRtree->nBytesPerCell = 8 + pRtree->nDim2*4;
/* Figure out the node size to use. */
rc = getNodeSize(db, pRtree, isCreate, pzErr);
if( rc ) goto rtreeInit_fail;
rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate);
if( rc ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
goto rtreeInit_fail;
}
*ppVtab = (sqlite3_vtab *)pRtree;
return SQLITE_OK;
rtreeInit_fail:
if( rc==SQLITE_OK ) rc = SQLITE_ERROR;
assert( *ppVtab==0 );
assert( pRtree->nBusy==1 );
rtreeRelease(pRtree);
return rc;
}
@@ -3751,7 +3896,7 @@ static u8 *rtreeCheckGetNode(RtreeCheck *pCheck, i64 iNode, int *pnNode){
** two tables are:
**
** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER)
** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER)
** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...)
**
** In both cases, this function checks that there exists an entry with
** IPK value iKey and the second column set to iVal.
@@ -3766,8 +3911,8 @@ static void rtreeCheckMapping(
int rc;
sqlite3_stmt *pStmt;
const char *azSql[2] = {
"SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?",
"SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?"
"SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1",
"SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1"
};
assert( bLeaf==0 || bLeaf==1 );
@@ -3951,6 +4096,7 @@ static int rtreeCheckTable(
RtreeCheck check; /* Common context for various routines */
sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
int bEnd = 0; /* True if transaction should be closed */
int nAux = 0; /* Number of extra columns. */
/* Initialize the context object */
memset(&check, 0, sizeof(check));
@@ -3966,11 +4112,21 @@ static int rtreeCheckTable(
bEnd = 1;
}
/* Find the number of auxiliary columns */
if( check.rc==SQLITE_OK ){
pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
if( pStmt ){
nAux = sqlite3_column_count(pStmt) - 2;
sqlite3_finalize(pStmt);
}
check.rc = SQLITE_OK;
}
/* Find number of dimensions in the rtree table. */
pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab);
if( pStmt ){
int rc;
check.nDim = (sqlite3_column_count(pStmt) - 1) / 2;
check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2;
if( check.nDim<1 ){
rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree");
}else if( SQLITE_ROW==sqlite3_step(pStmt) ){
+43 -5
View File
@@ -476,11 +476,11 @@ foreach {tn sql_template testdata} {
}
3 "UPDATE %CONF% t1 SET idx = 2 WHERE idx = 4" {
ROLLBACK 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6}
ABORT 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
IGNORE 1 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
FAIL 1 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
REPLACE 1 0 {1 1 2 3 4 2 4 5 6 7 3 3 4 5 6}
ROLLBACK 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6}
ABORT 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
FAIL 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
REPLACE 0 0 {1 1 2 3 4 2 4 5 6 7 3 3 4 5 6}
}
3 "UPDATE %CONF% t1 SET idx = ((idx+1)%5)+1 WHERE idx > 2" {
@@ -609,5 +609,43 @@ do_execsql_test 15.2 {
COMMIT;
}
# Test cases for the new auxiliary columns feature
#
do_catchsql_test 16.100 {
CREATE VIRTUAL TABLE t16 USING rtree(id,x0,x1,y0,+aux1,x1);
} {1 {Auxiliary rtree columns must be last}}
do_test 16.110 {
set sql {
CREATE VIRTUAL TABLE t16 USING rtree(
id, x00, x01, x10, x11, x20, x21, x30, x31, x40, x41
}
for {set i 12} {$i<=100} {incr i} {
append sql ", +a$i"
}
append sql ");"
execsql $sql
} {}
do_test 16.120 {
set sql {
CREATE VIRTUAL TABLE t16b USING rtree(
id, x00, x01, x10, x11, x20, x21, x30, x31, x40, x41
}
for {set i 12} {$i<=101} {incr i} {
append sql ", +a$i"
}
append sql ");"
catchsql $sql
} {1 {Too many columns for an rtree table}}
do_execsql_test 16.130 {
DROP TABLE IF EXISTS rt1;
CREATE VIRTUAL TABLE rt1 USING rtree(id, x1, x2, +aux);
INSERT INTO rt1 VALUES(1, 1, 2, 'aux1');
INSERT INTO rt1 VALUES(2, 2, 3, 'aux2');
INSERT INTO rt1 VALUES(3, 3, 4, 'aux3');
INSERT INTO rt1 VALUES(4, 4, 5, 'aux4');
SELECT * FROM rt1 WHERE id IN (1, 2, 3, 4);
} {1 1.0 2.0 aux1 2 2.0 3.0 aux2 3 3.0 4.0 aux3 4 4.0 5.0 aux4}
expand_all_sql db
finish_test
+1 -1
View File
@@ -81,7 +81,7 @@ do_faultsim_test rtree3-2 -faults oom* -prep {
do_malloc_test rtree3-3.prep {
faultsim_delete_and_reopen
execsql {
CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2, +a1, +a2);
INSERT INTO rt VALUES(NULL, 3, 5, 7, 9);
}
faultsim_save_and_close
+36 -3
View File
@@ -38,11 +38,20 @@ do_test rtree8-1.1.1 {
} {}
do_test rtree8-1.1.2 {
set res [list]
db eval { SELECT * FROM t1 } {
lappend res $x1 $x2
set rc [catch {
db eval { SELECT * FROM t1 } {
lappend res $x1 $x2
if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
}
} msg];
lappend rc $msg
set rc
} {1 {database table is locked}}
do_test rtree8-1.1.2b {
db eval { SELECT * FROM t1 ORDER BY +id } {
if {$id==3} { db eval { DELETE FROM t1 WHERE id>3 } }
}
set res
db eval {SELECT x1, x2 FROM t1}
} {1 3 2 4 3 5}
do_test rtree8-1.1.3 {
execsql { SELECT * FROM t1 }
@@ -170,5 +179,29 @@ do_test rtree8-5.4 {
} {}
do_rtree_integrity_test rtree8-5.5 t2
# 2018-05-24
# The following script caused an assertion fault and/or segfault
# prior to the fix that prevents simultaneous reads and writes on
# the same rtree virtual table.
#
do_test rtree8-6.1 {
db close
sqlite3 db :memory:
db eval {
PRAGMA page_size=512;
CREATE VIRTUAL TABLE t1 USING rtree(id,x1,x2,y1,y2);
WITH RECURSIVE c(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c WHERE x<49)
INSERT INTO t1 SELECT x, x, x+1, x, x+1 FROM c;
}
set rc [catch {
db eval {SELECT id FROM t1} x {
db eval {DELETE FROM t1 WHERE id=$x(id)}
}
} msg]
lappend rc $msg
} {1 {database table is locked}}
finish_test
+2 -2
View File
@@ -178,7 +178,7 @@ do_execsql_test 4.3 {
reset_db
do_execsql_test 5.1 {
CREATE TABLE t1(x PRIMARY KEY, y);
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2);
CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, +d1);
INSERT INTO t1(x) VALUES(1);
INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2
@@ -192,7 +192,7 @@ do_execsql_test 5.1 {
INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512
INSERT INTO t1(x) SELECT x+512 FROM t1; --1024
INSERT INTO rt SELECT x, x, x+1 FROM t1 WHERE x<=5;
INSERT INTO rt SELECT x, x, x+1, printf('x%04xy',x) FROM t1 WHERE x<=5;
}
do_rtree_integrity_test 5.1.1 rt
+80
View File
@@ -0,0 +1,80 @@
# 2018-05-16
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file contains tests for the r-tree module, specifically the
# auxiliary column mechanism.
if {![info exists testdir]} {
set testdir [file join [file dirname [info script]] .. .. test]
}
source [file join [file dirname [info script]] rtree_util.tcl]
source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return }
do_execsql_test rtreeH-100 {
CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1,+label,+other);
INSERT INTO t1(x0,x1,y0,y1,label) VALUES
(0,10,0,10,'lower-left corner'),
(0,10,90,100,'upper-left corner'),
(90,100,0,10,'lower-right corner'),
(90,100,90,100,'upper-right corner'),
(40,60,40,60,'center'),
(0,5,0,100,'left edge'),
(95,100,0,100,'right edge'),
(0,100,0,5,'bottom edge'),
(0,100,95,100,'top edge'),
(0,100,0,100,'the whole thing'),
(0,50,0,100,'left half'),
(51,100,0,100,'right half'),
(0,100,0,50,'bottom half'),
(0,100,51,100,'top half');
} {}
do_execsql_test rtreeH-101 {
SELECT * FROM t1_rowid ORDER BY rowid
} {1 1 {lower-left corner} {} 2 1 {upper-left corner} {} 3 1 {lower-right corner} {} 4 1 {upper-right corner} {} 5 1 center {} 6 1 {left edge} {} 7 1 {right edge} {} 8 1 {bottom edge} {} 9 1 {top edge} {} 10 1 {the whole thing} {} 11 1 {left half} {} 12 1 {right half} {} 13 1 {bottom half} {} 14 1 {top half} {}}
do_execsql_test rtreeH-102 {
SELECT * FROM t1 WHERE rowid=5;
} {5 40.0 60.0 40.0 60.0 center {}}
do_execsql_test rtreeH-103 {
SELECT * FROM t1 WHERE label='center';
} {5 40.0 60.0 40.0 60.0 center {}}
do_rtree_integrity_test rtreeH-110 t1
do_execsql_test rtreeH-120 {
SELECT label FROM t1 WHERE x1<=50 ORDER BY id
} {{lower-left corner} {upper-left corner} {left edge} {left half}}
do_execsql_test rtreeH-121 {
SELECT label FROM t1 WHERE x1<=50 AND label NOT LIKE '%corner%' ORDER BY id
} {{left edge} {left half}}
do_execsql_test rtreeH-200 {
WITH RECURSIVE
c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<99),
c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<99)
INSERT INTO t1(id, x0,x1,y0,y1,label)
SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2;
} {}
do_execsql_test rtreeH-210 {
SELECT label FROM t1 WHERE x0>=48 AND x1<=50 AND y0>=48 AND y1<=50
ORDER BY id;
} {box-48,48 box-49,48 box-48,49 box-49,49}
do_execsql_test rtreeH-300 {
UPDATE t1 SET label='x'||label
WHERE x0>=49 AND x1<=50 AND y0>=49 AND y1<=50;
SELECT label FROM t1 WHERE x0>=48 AND x1<=50 AND y0>=48 AND y1<=50
ORDER BY id;
} {box-48,48 box-49,48 box-48,49 xbox-49,49}
finish_test
+61 -56
View File
@@ -1,5 +1,5 @@
C In\sthe\sCLI,\sallow\scomment\slines\sthat\sbegin\swith\s'#',\sbut\sonly\sin\sa\scontext\nwhere\sa\sdot-command\sis\sallowed.\s\sIn\sother\swords,\s'#'\sat\sthe\sbeginning\sof\sa\nline\sin\sthe\smiddle\sof\san\sSQL\sstatement\sis\sjust\spart\sof\sthe\sSQL.
D 2018-05-12T23:56:22.493
C Version\s3.24.0
D 2018-06-04T19:24:41.225
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
@@ -12,7 +12,8 @@ F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
F autoconf/Makefile.am f8c274ee0022cb6d48ff103ab6c6b0733c41b3b02cb8566228dfd602f701e0c2
F autoconf/Makefile.am 465fb475ee5a4b8a63d26c889cb36a4edbff0325b6859eb29a13cdf5c91b005c
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
F autoconf/Makefile.msc 6a46d0659d6e4a25346102bcba40a7fb4b0b8b2dc4faabdf0187488c6dd580d6
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
F autoconf/README.txt 4f04b0819303aabaa35fff5f7b257fb0c1ef95f1
@@ -44,8 +45,8 @@ F ext/async/sqlite3async.c 0f3070cc3f5ede78f2b9361fb3b629ce200d7d74
F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef
F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3
F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4
F ext/expert/expert1.test 87e54effda905d991edfe4bcd28098460a568246129ab7263f71b25420ea727f
F ext/expert/sqlite3expert.c 95fdee74be2912d962951d984f1123e55d3f44bd643da7a48ff6ea9426a47f69
F ext/expert/expert1.test baa05800dc1c569faa7ce6232cead0fcedc07fea038b3a2489eaaf710831d546
F ext/expert/sqlite3expert.c 89b7b59be610b929958db02416539a46ac088fd84f81623c4190aff62e92c3c4
F ext/expert/sqlite3expert.h af6354f8ee5c9e025024e63fec3bd640a802afcc3099a44d804752cf0791d811
F ext/expert/test_expert.c d56c194b769bdc90cf829a14c9ecbc1edca9c850b837a4d0b13be14095c32a72
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
@@ -274,13 +275,13 @@ F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c
F ext/misc/closure.c fe928228e8dfb2f00227311c203ccba9c2e5561f4f6de6da87e5b4a30cd8af15
F ext/misc/completion.c e75b8886a2531f9a7ec02dab5f179bb37e6bd46b5da7665a6cbf2dfbe2daa483
F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189
F ext/misc/csv.c d1e324fac3f87f818d684a3d752d1ef76dbcd4fc0db6746ac4034c19d0bcda21
F ext/misc/csv.c 65297bcce8d5acd5aadef42acbe739aef5a2ef5e74c7b73361ca19f3e21de657
F ext/misc/dbdump.c 69ef1be5b210538f77dfcc6fcb55b4b5f5e98b1e0bcfd67d818711e10761db4d
F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0e3
F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
F ext/misc/json1.c 02f5f0d9c131df79f4ee168d2b426f0f0d273b7771fc0bb5293c4e7692d9a2ee
F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
@@ -355,24 +356,25 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c bc61010e978b5b8ae6dbb90274a2fbb5db5ff5e2880b5c6e8abd48eea77264db
F ext/rtree/rtree.c cb6d4bd43c118354fe5b5213843da058259467ecdbac0c6f71ead0fd89acf4ec
F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
F ext/rtree/rtree1.test 47e2095bebea6813754fd7afa6a20e2b7b4ebcd5cb7dbcb6932b6c9f86bbf972
F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
F ext/rtree/rtree3.test 2cafe8265d1ff28f206fce88d114f208349df482
F ext/rtree/rtree3.test 4ee5d7df86040efe3d8d84f141f2962a7745452200a7cba1db06f86d97050499
F ext/rtree/rtree4.test 304de65d484540111b896827e4261815e5dca4ce28eeecd58be648cd73452c4b
F ext/rtree/rtree5.test 49c9041d713d54560b315c2c7ef7207ee287eba1b20f8266968a06f2e55d3142
F ext/rtree/rtree6.test 593e0d36510d5ac1d1fb39b018274ff17604fe8fdca8cf1f8e16559cea1477f4
F ext/rtree/rtree7.test c8fb2e555b128dd0f0bdb520c61380014f497f8a23c40f2e820acc9f9e4fdce5
F ext/rtree/rtree8.test 649f5a37ec656028a4a32674b9b1183104285a7625a09d2a8f52a1cef72c93f2
F ext/rtree/rtree8.test 924926d7c64ac59fcca0809de472d9dd73c612f54daae1cf992bdd7dac90305b
F ext/rtree/rtree9.test c646f12c8c1c68ef015c6c043d86a0c42488e2e68ed1bb1b0771a7ca246cbabf
F ext/rtree/rtreeA.test 20623ca337ca3bd7e008cc9fb49e44dbe97f1a80b238e10a12bb4afcd0da3776
F ext/rtree/rtreeB.test 4cec297f8e5c588654bbf3c6ed0903f10612be8a2878055dd25faf8c71758bc9
F ext/rtree/rtreeC.test 55e40c4bd9735d9944280f0e664f39374e71bcd9cd3fe4e82786d20b48017fb5
F ext/rtree/rtreeC.test 128928549d22b65c381ab1366760d08703cd75e34f6a7a506ece38f9330b7282
F ext/rtree/rtreeD.test fe46aa7f012e137bd58294409b16c0d43976c3bb92c8f710481e577c4a1100dc
F ext/rtree/rtreeE.test e65d3fc625da1800b412fc8785817327d43ccfec5f5973912d8c9e471928caa9
F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd450ed331
F ext/rtree/rtreeG.test 1b9ca6e3effb48f4161edaa463ddeaa8fca4b2526d084f9cbf5dbe4e0184939c
F ext/rtree/rtreeH.test aa08cc4fa8005b4c67446c7110205055b4d6da90e760e6f44b82dfa4cdf8d87a
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b587936f5f6bceed
F ext/rtree/rtreecheck.test 4d29103d1e16fcbf90135d1c637b833688492b063b2971dfb5dc6ba76555cfee
@@ -430,34 +432,34 @@ F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c cf7a8af45cb0ace672f47a1b29ab24092a9e8cd8d945a9974e3b5d925f548594
F src/analyze.c 71fbbeb7b25417592f54d869fe90c28b48e4cecb9926ef9b06d90fb0aec48941
F src/attach.c 4a3138bd771d5426ae4344d8d5e900440af29fabc5ec2f39f69a45010dfbccd7
F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
F src/auth.c a38f3c63c974787ecf75e3213f8cac6568b9a7af7591fb0372ec0517dd16dca8
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 8270813c8f0ca91b2802e88ded3755d04ee962a923d431c13bcb6cf3e0c18f63
F src/btree.c 44405d03a05496e13b40b3a208bcf941c42c815da90d6ff4b04267a6985e5eb7
F src/btree.h 448f15b98ea85dcf7e4eb76f731cadb89636c676ad25dfaac6de77cd66556598
F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
F src/build.c 50ff3e0fa07646b4d797aae0f773efcdb7602f6a5e2f5da27856503f35200889
F src/callback.c fe677cb5f5abb02f7a772a62a98c2f516426081df68856e8f2d5f950929b966a
F src/build.c 5fc41458505331bfb0c175f40b9a13cb335f826bed3ae311aaae000c132d7b16
F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 849d4cebe008cfc6e4799b034a172b4eaf8856b100739632a852732ba66eee48
F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6
F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
F src/delete.c b0f90749e22d5e41a12dbf940f4811138cf97da54b46b737089b93eb64a2896f
F src/expr.c af4a81a385277510bfc56df87c25d76fc365f98c33bc8797c4a8d84b88e31013
F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
F src/expr.c 16f90ae2af2a100bc430a89184afde54878d82f18267e8d00bc4f33e695a7c57
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331
F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
F src/func.c e2e3c02621a528a472933fd4733a5da635676f1461be73293f6e9f62f18d4eaa
F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128
F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 33a2c72b6182e8ddf697d604cc087c77ff5fc512a32b8b624641d41b390e249e
F src/insert.c 76b1dc902e4c3930d9a17a40cd8ee2e94b1fd8cce766672caef164a6d5d4df1d
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b
F src/main.c b56b2d62d5d11e3f5100b25fca34c13c62a0fe73941f6873454a7fa8a454170d
F src/main.c 0402e234155e0aad75fe6cd204864f492495be8605a50b4b3d4d72895cced3ce
F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@@ -477,28 +479,28 @@ F src/os.c 1cb0d1d1b3a4267966dee6e292d2b2cdf88e47c0c59cebff27ecafac052dd165
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c 2b53b0b8ddc580db096252c721729e5f5f2f355b4fc056f8f3fb328aeb3c9e8a
F src/os_unix.c c230a7a24766320d8414afd087edcd43e499fb45e86361f6f4f464f343d965a9
F src/os_win.c ac29c25cde4cfb4adacc59cdec4aa45698ca0e29164ea127859585ccd9faa354
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 1bb6a57fa0465296a4d6109a1a64610a0e7adde1f3acf3ef539a9d972908ce8f
F src/pager.h c571b064df842ec8f2e90855dead9acf4cbe0d1b2c05afe0ef0d0145f7fd0388
F src/parse.y 07784439d25f0bc64a656eece4caecc549b147d213f513cdbeb8430345ec2911
F src/parse.y 0b81472496809693a139067fea1fe3f14a7be8aa26c8f18bb327034d1252a06a
F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd
F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
F src/pragma.c c0d13c0e82a9197aef5533d63300c5b0c8a216ae1fd14ada64e1f12f398d7e82
F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
F src/prepare.c 95a9dba7a5d032039a77775188cb3b6fb17f2fa1a0b7cd915b30b4b823383ffa
F src/printf.c 74ca0348796b490cdc56c85a8fb1abaa423c15c869712f54bf49fca65aa1dda1
F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9
F src/resolve.c 14602f46800ba182ea6a490e0f304127d29ac1f724bdadcc639e25d3223fcf6e
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c a35d462ee7a3c0856ad7a9d9c8921fbf3d91d911a8f39ad9d61302eb43b24a71
F src/shell.c.in df40a09c4098d050bf5a008caa9ca8f25eed8ff9a8468d39b1f4d8a778cd324a
F src/sqlite.h.in ef7e6fae65cb40ba004abf090ea491751295c11e64b1446322813d3b473b9400
F src/select.c 3291892add3a8f01dc3754e40ef9e30ad22c78e3404a388ae58f0390a1fb29eb
F src/shell.c.in c29cb307d6275131e6f9874e0fa73f87acf40a22c4a82faba2059a93b4d294d1
F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
F src/sqliteInt.h 5abdade4744cf3bd567afb65bb144bb3c61f6132f86813b995a5ca79c7b584e8
F src/sqliteInt.h d2bd297dba08f2390a91c31ff775e0964e9663df5b2910a569fe6f830b8b2beb
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -530,7 +532,7 @@ F src/test_intarray.c 988fc61cb0ff539f4172c0d95f15287c92516f64
F src/test_intarray.h f3b7672f5d1056eac563c0d6ea8480a660b1475c
F src/test_journal.c 619f2aa10e0d7a5f87c0f06825bc61dfce1c6b9c7f3ad990fb13de6c3b8874a3
F src/test_loadext.c 337056bae59f80b9eb00ba82088b39d0f4fe6dfd
F src/test_malloc.c 5201422e2403e66a7a9c2b7d8df806acd8d2a0429822adb7e932f324e7b5b3c6
F src/test_malloc.c dec0aa821b230773aeb3dd11d652c1193f7cedb18a20b25659bc672288115242
F src/test_md5.c 7268e1e8c399d4a5e181b64ac20e1e6f3bc4dd9fc87abac02db145a3d951fa8c
F src/test_multiplex.c e054459f7633f3ff8ce1245da724f9a8be189e4e
F src/test_multiplex.h 5436d03f2d0501d04f3ed50a75819e190495b635
@@ -558,26 +560,26 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c bbde32eac9eb1280f5292bcdfef66f5a57e43176cbf9347e0efab9f75e133f97
F src/treeview.c 2c5c4bc0a443401db5fd621542150452ddf5055d38edd4eef868bc2b6bfb0260
F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995
F src/update.c 5be2f501ddc704fc04183bdb28b25eab930bb8553d973429a089ec94fa85cf2b
F src/upsert.c ae4a4823b45c4daf87e8aea8c0f582a8844763271f5ed54ee5956c4c612734f4
F src/update.c 46dc24c6158446aaab45caee09b6d99327cb479268b83ffeb5b701823da3b67b
F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
F src/vacuum.c 37730af7540033135909ecaee3667dddec043293428d8718546d0d64ba4a5025
F src/vdbe.c 066a4e1de2ed83e253adfd2e97a684cf562eaa41d31ee7f3d3e4c8aea4485a55
F src/vdbe.h d970d9738efdd09cb2df73e3a40856e7df13e88a3486789c49fcdd322c9eb8a2
F src/vdbeInt.h 95f7adfdc5c8f1353321f55a6c5ec00a90877e3b85af5159e393afb41ff54110
F src/vdbeapi.c 29d2baf9c1233131ec467d7bed1b7c8a03c27579048d768c4b04acf427838858
F src/vdbeaux.c f1cb5ae6e42c54d4991e2951e5293c1e18bad6847056e9b17622fbf6b17964a9
F src/vdbe.c 71e5a72d89eabf7f88ef0ad4a429d3c3ee5d10de76af3818c47b275a6b3a9097
F src/vdbe.h e3f43bcc27ff30b0f25a6104d0cb5657e1c4b5e1b5cd2dd2216d5bcc2156a746
F src/vdbeInt.h 42d3e65ea0c664f6d9bc9a53de645c0baf8566ff0188409ff3b8d2abc327bc17
F src/vdbeapi.c 765a0bbe01311626417de6cb743f7f25f9f98435c98a9df4bb0714d11014633d
F src/vdbeaux.c b00d35805a2b326d1371ab7ce8f3a95c8af35b1431367ffe482fc2c735d69fb1
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 0cbe9b9560e42b72983cf9e1bceba48f297e51142bfb6b57f3747cf60106b92d
F src/vdbemem.c 803323406d8623a7619ea5d5f74016697eeaed19c02b98ce9c3013e77dbe1c38
F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a
F src/vtab.c 10ea07dec111de6fb0a4fc87a7ffa4c65fdc088a19dbfaf7d6f2b128f2e8eb7b
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c aa9cffc7a2bad6b826a86c8562dd4978398720ed41cb8ee7aa9d054eb8b456a0
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
F src/where.c d89b1aa56a75a572cd60ad27ec0fe5958d5f98b0f4391a89c72811287be7c439
F src/where.c 60ec752fcbe9f9e0271ac60548d159a540a1ee47a4f9fedc85e88a3d0e392dd1
F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53
F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8
F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a
@@ -625,7 +627,7 @@ F test/auth.test 3d6cd8f3978ba55b1202574e6ecd79c6e00914ca44b9bfd6c1fe6fb873fcac8
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
F test/autoinc.test 83aad64411583aac9ff0b629159ab4662029ab4e3f47090fce4efd132b304484
F test/autoinc.test 9d202b7dce6571e52b744138eff12610214501acd635abdd72d18736cd06fd22
F test/autoindex1.test a09958fa756129af10b6582bcbf3cbdf11e305e027b393f393caef801159dee0
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test 2dd997d6590438b53e4f715f9278aa91c9299cf3f81246a0915269c35beb790e
@@ -738,7 +740,7 @@ F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/csv01.test b99db7e57ee66fb3aa6e5d25af119003bee90bf679c5885711cbf7374f025b73
F test/csv01.test 6e1445b3207d574cff22fc41a8e549dfcf2466ee90546ada97d22a90fa89eb58
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 0078ae1ded4afcf5eb80d06e3a72b6e1c3f1a646aab26eeb583b0a9ec6f0d56e
@@ -771,7 +773,7 @@ F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
F test/e_dropview.test 21ce09c361227ddbc9819a5608ee2700c276bdd5
F test/e_expr.test ca8896601ade1e27c6559614c7f32c63d44636fdfa720436a160f09b8bf66c89
F test/e_fkey.test dcdc6ad26b1d4f07636208de4c1c22aae7c0597a685a6c10fe6da91f3191dd96
F test/e_fkey.test 9778696ef9fceacebed8d482d02b47287981faaedf6f73db563ea8a7afb546da
F test/e_fts3.test 8cf40550bb088a6aa187c818c00fabe26ef82900a4cd5c66b427ccafe28bedaa
F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e
F test/e_reindex.test 2bebf7b393e519198b7c654407221cf171a439b8
@@ -1021,7 +1023,7 @@ F test/journal3.test c9c29883f5bf535ae82ae21c472df6263806a22e467b6db7cd0d6d54530
F test/jrnlmode.test a6693f2bed4541a21e703aaa37bb3e10de154130645952933b82b2dec0a8b539
F test/jrnlmode2.test 8759a1d4657c064637f8b079592651530db738419e1d649c6df7048cd724363d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test 24e97954e3bd6404f3715888c7f8f835e36e19c7ae6513b5d9ab2d381498962d
F test/json101.test b40a9f5395d8e669b0bc3eb550ad2ae9e5ada01fbce23c446c2a30a305a6d575
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
@@ -1050,7 +1052,7 @@ F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
F test/malloc.test 18dd1c4188c81ca79cf123527c71b19ee0c31feb9947fdffb0dc6ceb1436816a
F test/malloc3.test 6e88bae6312854a4adb4ecc2a6a5ea8c59b4db778b724ba718e1c43fc8c3c136
F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
F test/malloc5.test f6eb6eca07a4c75f2897bf43a404689b6295bb95ab2e07d4b52eda743f925a27
F test/malloc5.test 2e4ad7684a13389a44a840499cd47173a8d05f22f082d7d083eece433a7a64eb
F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151
F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a
F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d
@@ -1087,7 +1089,7 @@ F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3
F test/misc5.test 60e1fc758a93cacd19eb2fafcd1d40d150a05047546c7a92389c98047d621901
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test 567e223b6497da2226a0340befaf2d663c91ad57a48aede21a35a984a2882d41
F test/misc7.test 349855706310f0de6b91645d199f6874f518627fd057743fa4e3689b60d06efc
F test/misc8.test 8fb0f31d7a8aed484d759773ab8ad12ec746a477f4a67394a4af0e677494c3ca
F test/misuse.test 9e7f78402005e833af71dcab32d048003869eca5abcaccc985d4f8dc1d86bcc7
F test/mjournal.test 9d86e697dcbc5da2c4e8caba9b176b5765fe65e80c88c278b8c09a917e436795
@@ -1128,7 +1130,7 @@ F test/orderby6.test 8b38138ab0972588240b3fca0985d2e400432859
F test/orderby7.test 3d1383d52ade5b9eb3a173b3147fdd296f0202da
F test/orderby8.test 23ef1a5d72bd3adcc2f65561c654295d1b8047bd
F test/orderby9.test 87fb9548debcc2cd141c5299002dd94672fa76a3
F test/oserror.test b32dc34f2363ef18532e3a0a7358e3e7e321974f
F test/oserror.test e7b3416be4b9d5dd2fe0b42dd394daaddbb6c83eeec1f0e47b120b53e0ad3ace
F test/ossfuzz.c c4c4547e2c92ac52f10038b073a03248251a23c1c559728f63a18aeca0e79f03
F test/ossshell.c f125c5bd16e537a2549aa579b328dd1c59905e7ab1338dfc210e755bb7b69f17
F test/ovfl.test 199c482696defceacee8c8e0e0ef36da62726b2f
@@ -1171,7 +1173,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl 5f15ab8056799e9a6e26a310d49236d2e774d6a30d0ec74601e18d4ce146b79c x
F test/resetdb.test 7fda92e443233208ec5e1825b176a9df63fb5bf962248e08b76eb4296c630cdf
F test/resetdb.test 2107b34a8c437183f48eb833905df43818160a55f4ac69bbaf54f356fb2b27bd
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6
@@ -1239,7 +1241,7 @@ F test/sharedA.test 49d87ec54ab640fbbc3786ee3c01de94aaa482a3a9f834ad3fe92770eb69
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
F test/shared_err.test 32634e404a3317eeb94abc7a099c556a346fdb8fb3858dbe222a4cbb8926a939
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
F test/shell1.test e2f7d375ae80eb16590af23d6c40cd0140b6d1f92642c1b71eb94630a144ee08
F test/shell1.test 50154b0c4779df435b9e60ca60104b05f1cc217eab1aa383131359329e73d939
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
F test/shell4.test 89ad573879a745974ff2df20ff97c5d6ffffbd5d
@@ -1277,7 +1279,7 @@ F test/speed3.test 694affeb9100526007436334cf7d08f3d74b85ef
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
F test/speed4p.test 377a0c48e5a92e0b11c1c5ebb1bc9d83a7312c922bc0cb05970ef5d6a96d1f0c
F test/speedtest1.c 20cc4028b0e88392b5a635c2ea5d5e777d569bf7258aead37f8be7a886c38344
F test/speedtest1.c cc7e6b4a7c9f3e3d1a497ae3f75236a832a2ce0f6a9b017f95d996c821605bfb
F test/spellfix.test 951a6405d49d1a23d6b78027d3877b4a33eeb8221dcab5704b499755bb4f552e
F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
@@ -1605,7 +1607,7 @@ F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286c
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
F test/wherelimit.test 1dee70c9cc147330156d75e23de88f771e624998b03ae316cb64e1d249f129d8
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
F test/wherelimit2.test be78ba3aa1831c6358fd7d5b9809bfd520f0c2a7d63a295e8f182e140ff137c3
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2aeee74
@@ -1659,7 +1661,7 @@ F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9
F tool/mkkeywordhash.c 20f366ad3794e1db42e333a6f35fa41a024f2e3528579c9d58eb13eaa3ab4913
F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 4ee2a30ccbd900dc4d5cdb61bdab87cd2166cd2affcc78c9cc0b8d22a65b2eee
F tool/mkopcodeh.tcl 17d1ccc05a926e19e3a9679ea3e4d1aaa15ba753e2fa7363e6e81c80e0ef8b86
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd
F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5
@@ -1686,7 +1688,7 @@ F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
F tool/spaceanal.tcl 4bfd19aad7eb3ce0372ef0255f58035e0bba4ff5e9acfd763a10c6fb365c8dec
F tool/speed-check.sh 4ff9b095cf1a7643f0264e7fb7d23f0b12b7cce587a9de315877c378e90eeaf4
F tool/speed-check.sh 27c7fe178d5b2f7c90a04a127907acda0bfe637fa85b13c43e03e5ed39b008b6
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
@@ -1728,7 +1730,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 13e7300a37e379eac564594d78d3f039fd25737493b3b627ef02fab57a6c98e1
R 6b32792e712eff37702825b507b2e9b6
P 1ecb3aa13de5c8dc611b814ff34010de0bd90aae73d88aa37a59c4627be4cc2d
R 2db4b8b40a57a71d528932145db72c5a
T +bgcolor * #d0c0ff
T +sym-release *
T +sym-version-3.24.0 *
U drh
Z d7c29ce2018cfc34028d7ed7f7fd8bc3
Z 1c60c6ad1e28023fcabbb88fe23d7708
+1 -1
View File
@@ -1 +1 @@
4ee136d6d2e029dad8371faf659d3a0bc0ac6ae76940db81d333848545bc990f
c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca
+1 -1
View File
@@ -150,6 +150,7 @@ void sqlite3AuthRead(
int iDb; /* The index of the database the expression refers to */
int iCol; /* Index of column in table */
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
if( db->xAuth==0 ) return;
iDb = sqlite3SchemaToIndex(pParse->db, pSchema);
if( iDb<0 ){
@@ -158,7 +159,6 @@ void sqlite3AuthRead(
return;
}
assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER );
if( pExpr->op==TK_TRIGGER ){
pTab = pParse->pTriggerTab;
}else{
+5 -1
View File
@@ -864,7 +864,11 @@ static int btreeRestoreCursorPosition(BtCursor *pCur){
** back to where it ought to be if this routine returns true.
*/
int sqlite3BtreeCursorHasMoved(BtCursor *pCur){
return pCur->eState!=CURSOR_VALID;
assert( EIGHT_BYTE_ALIGNMENT(pCur)
|| pCur==sqlite3BtreeFakeValidCursor() );
assert( offsetof(BtCursor, eState)==0 );
assert( sizeof(pCur->eState)==1 );
return CURSOR_VALID != *(u8*)pCur;
}
/*
+4 -2
View File
@@ -2843,6 +2843,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeCoverage(v);
regRecord = sqlite3GetTempReg(pParse);
sqlite3MultiWrite(pParse);
sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0);
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
@@ -2856,12 +2857,13 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
if( IsUniqueIndex(pIndex) ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeGoto(v, j2);
int j2 = sqlite3VdbeGoto(v, 1);
addr2 = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeVerifyAbortable(v, OE_Abort);
sqlite3VdbeAddOp4Int(v, OP_SorterCompare, iSorter, j2, regRecord,
pIndex->nKeyCol); VdbeCoverage(v);
sqlite3UniqueConstraint(pParse, OE_Abort, pIndex);
sqlite3VdbeJumpHere(v, j2);
}else{
addr2 = sqlite3VdbeCurrentAddr(v);
}
+2
View File
@@ -406,10 +406,12 @@ FuncDef *sqlite3FindFunction(
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
u8 *z;
pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy((char*)&pBest[1], zName, nName+1);
for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z];
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
+7 -4
View File
@@ -553,13 +553,16 @@ void sqlite3DeleteFrom(
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
sqlite3MayAbort(pParse);
if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){
pParse->isMultiWrite = 0;
if( eOnePass==ONEPASS_SINGLE ){
sqlite3VdbeAddOp1(v, OP_Close, iTabCur);
if( sqlite3IsToplevel(pParse) ){
pParse->isMultiWrite = 0;
}
}
sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
}else
#endif
{
+1 -1
View File
@@ -3993,7 +3993,7 @@ expr_code_doover:
case TK_COLLATE:
case TK_UPLUS: {
pExpr = pExpr->pLeft;
goto expr_code_doover;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. OSSFuzz. */
}
case TK_TRIGGER: {
+7
View File
@@ -331,6 +331,12 @@ static void fkLookupParent(
int iCur = pParse->nTab - 1; /* Cursor number to use */
int iOk = sqlite3VdbeMakeLabel(v); /* jump here if parent key found */
sqlite3VdbeVerifyAbortable(v,
(!pFKey->isDeferred
&& !(pParse->db->flags & SQLITE_DeferFKs)
&& !pParse->pToplevel
&& !pParse->isMultiWrite) ? OE_Abort : OE_Ignore);
/* If nIncr is less than zero, then check at runtime if there are any
** outstanding constraints to resolve. If there are not, there is no need
** to check if deleting this row resolves any outstanding violations.
@@ -738,6 +744,7 @@ void sqlite3FkDropTable(Parse *pParse, SrcList *pName, Table *pTab){
** constraints are violated.
*/
if( (db->flags & SQLITE_DeferFKs)==0 ){
sqlite3VdbeVerifyAbortable(v, OE_Abort);
sqlite3VdbeAddOp2(v, OP_FkIfZero, 0, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
sqlite3HaltConstraint(pParse, SQLITE_CONSTRAINT_FOREIGNKEY,
+22 -1
View File
@@ -226,11 +226,26 @@ static int autoIncBegin(
Table *pTab /* The table we are writing to */
){
int memId = 0; /* Register holding maximum rowid */
assert( pParse->db->aDb[iDb].pSchema!=0 );
if( (pTab->tabFlags & TF_Autoincrement)!=0
&& (pParse->db->mDbFlags & DBFLAG_Vacuum)==0
){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
AutoincInfo *pInfo;
Table *pSeqTab = pParse->db->aDb[iDb].pSchema->pSeqTab;
/* Verify that the sqlite_sequence table exists and is an ordinary
** rowid table with exactly two columns.
** Ticket d8dc2b3a58cd5dc2918a1d4acb 2018-05-23 */
if( pSeqTab==0
|| !HasRowid(pSeqTab)
|| IsVirtual(pSeqTab)
|| pSeqTab->nCol!=2
){
pParse->nErr++;
pParse->rc = SQLITE_CORRUPT_SEQUENCE;
return 0;
}
pInfo = pToplevel->pAinc;
while( pInfo && pInfo->pTab!=pTab ){ pInfo = pInfo->pNext; }
@@ -1405,6 +1420,7 @@ void sqlite3GenerateConstraintChecks(
Expr *pExpr = pCheck->a[i].pExpr;
if( aiChng && checkConstraintUnchanged(pExpr, aiChng, pkChng) ) continue;
allOk = sqlite3VdbeMakeLabel(v);
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3ExprIfTrue(pParse, pExpr, allOk, SQLITE_JUMPIFNULL);
if( onError==OE_Ignore ){
sqlite3VdbeGoto(v, ignoreDest);
@@ -1514,6 +1530,7 @@ void sqlite3GenerateConstraintChecks(
/* Check to see if the new rowid already exists in the table. Skip
** the following conflict logic if it does not. */
VdbeNoopComment((v, "uniqueness check for ROWID"));
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regNewData);
VdbeCoverage(v);
@@ -1726,6 +1743,7 @@ void sqlite3GenerateConstraintChecks(
/* Check to see if the new index entry will be unique */
sqlite3ExprCachePush(pParse);
sqlite3VdbeVerifyAbortable(v, onError);
sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
regIdx, pIdx->nKeyCol); VdbeCoverage(v);
@@ -1812,10 +1830,12 @@ void sqlite3GenerateConstraintChecks(
default: {
Trigger *pTrigger = 0;
assert( onError==OE_Replace );
sqlite3MultiWrite(pParse);
if( db->flags&SQLITE_RecTriggers ){
pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
}
if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
sqlite3MultiWrite(pParse);
}
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
regR, nPkField, 0, OE_Replace,
(pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur);
@@ -2335,6 +2355,7 @@ static int xferOptimization(
emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v);
if( pDest->iPKey>=0 ){
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
sqlite3VdbeVerifyAbortable(v, onError);
addr2 = sqlite3VdbeAddOp3(v, OP_NotExists, iDest, 0, regRowid);
VdbeCoverage(v);
sqlite3RowidConstraint(pParse, onError, pDest);
+34 -9
View File
@@ -1808,11 +1808,13 @@ int sqlite3_create_function_v2(
#endif
sqlite3_mutex_enter(db->mutex);
if( xDestroy ){
pArg = (FuncDestructor *)sqlite3DbMallocZero(db, sizeof(FuncDestructor));
pArg = (FuncDestructor *)sqlite3Malloc(sizeof(FuncDestructor));
if( !pArg ){
sqlite3OomFault(db);
xDestroy(p);
goto out;
}
pArg->nRef = 0;
pArg->xDestroy = xDestroy;
pArg->pUserData = p;
}
@@ -1820,7 +1822,7 @@ int sqlite3_create_function_v2(
if( pArg && pArg->nRef==0 ){
assert( rc!=SQLITE_OK );
xDestroy(p);
sqlite3DbFree(db, pArg);
sqlite3_free(pArg);
}
out:
@@ -1858,6 +1860,28 @@ int sqlite3_create_function16(
#endif
/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context. The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
** for name resolution but are actually overloaded by the xFindFunction
** method of virtual tables.
*/
static void sqlite3InvalidFunction(
sqlite3_context *context, /* The function calling context */
int NotUsed, /* Number of arguments to the function */
sqlite3_value **NotUsed2 /* Value of each argument */
){
const char *zName = (const char*)sqlite3_user_data(context);
char *zErr;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
zErr = sqlite3_mprintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
}
/*
** Declare that a function has been overloaded by a virtual table.
**
@@ -1875,7 +1899,8 @@ int sqlite3_overload_function(
const char *zName,
int nArg
){
int rc = SQLITE_OK;
int rc;
char *zCopy;
#ifdef SQLITE_ENABLE_API_ARMOR
if( !sqlite3SafetyCheckOk(db) || zName==0 || nArg<-2 ){
@@ -1883,13 +1908,13 @@ int sqlite3_overload_function(
}
#endif
sqlite3_mutex_enter(db->mutex);
if( sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)==0 ){
rc = sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
0, sqlite3InvalidFunction, 0, 0, 0);
}
rc = sqlite3ApiExit(db, rc);
rc = sqlite3FindFunction(db, zName, nArg, SQLITE_UTF8, 0)!=0;
sqlite3_mutex_leave(db->mutex);
return rc;
if( rc ) return SQLITE_OK;
zCopy = sqlite3_mprintf(zName);
if( zCopy==0 ) return SQLITE_NOMEM;
return sqlite3_create_function_v2(db, zName, nArg, SQLITE_UTF8,
zCopy, sqlite3InvalidFunction, 0, 0, sqlite3_free);
}
#ifndef SQLITE_OMIT_TRACE
+1 -1
View File
@@ -3779,7 +3779,7 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
do{
err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size);
}while( err==EINTR );
if( err ) return SQLITE_IOERR_WRITE;
if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE;
#else
/* If the OS does not have posix_fallocate(), fake it. Write a
** single byte to the last byte in each block that falls entirely
+2
View File
@@ -467,6 +467,7 @@ cmd ::= select(X). {
}
}
%ifndef SQLITE_OMIT_CTE
select(A) ::= WITH wqlist(W) selectnowith(X). {
Select *p = X;
if( p ){
@@ -487,6 +488,7 @@ select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). {
}
A = p;
}
%endif /* SQLITE_OMIT_CTE */
select(A) ::= selectnowith(X). {
Select *p = X;
if( p ){
+13 -1
View File
@@ -967,11 +967,21 @@ char *sqlite3StrAccumFinish(StrAccum *p){
return p->zText;
}
/*
** This singleton is an sqlite3_str object that is returned if
** sqlite3_malloc() fails to provide space for a real one. This
** sqlite3_str object accepts no new text and always returns
** an SQLITE_NOMEM error.
*/
static sqlite3_str sqlite3OomStr = {
0, 0, 0, 0, 0, SQLITE_NOMEM, 0
};
/* Finalize a string created using sqlite3_str_new().
*/
char *sqlite3_str_finish(sqlite3_str *p){
char *z;
if( p ){
if( p!=0 && p!=&sqlite3OomStr ){
z = sqlite3StrAccumFinish(p);
sqlite3_free(p);
}else{
@@ -1040,6 +1050,8 @@ sqlite3_str *sqlite3_str_new(sqlite3 *db){
if( p ){
sqlite3StrAccumInit(p, 0, 0, 0,
db ? db->aLimit[SQLITE_LIMIT_LENGTH] : SQLITE_MAX_LENGTH);
}else{
p = &sqlite3OomStr;
}
return p;
}
+24 -21
View File
@@ -75,29 +75,31 @@ static void resolveAlias(
assert( pOrig!=0 );
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return;
if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
ExprSetProperty(pDup, EP_Alias);
if( pDup!=0 ){
if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
}
ExprSetProperty(pDup, EP_Alias);
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
** The pExpr->u.zToken might point into memory that will be freed by the
** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
pExpr->flags |= EP_MemToken;
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself,
** allowing it to be repopulated by the memcpy() on the following line.
** The pExpr->u.zToken might point into memory that will be freed by the
** sqlite3DbFree(db, pDup) on the last line of this block, so be sure to
** make a copy of the token before doing the sqlite3DbFree().
*/
ExprSetProperty(pExpr, EP_Static);
sqlite3ExprDelete(db, pExpr);
memcpy(pExpr, pDup, sizeof(*pExpr));
if( !ExprHasProperty(pExpr, EP_IntValue) && pExpr->u.zToken!=0 ){
assert( (pExpr->flags & (EP_Reduced|EP_TokenOnly))==0 );
pExpr->u.zToken = sqlite3DbStrDup(db, pExpr->u.zToken);
pExpr->flags |= EP_MemToken;
}
sqlite3DbFree(db, pDup);
}
sqlite3DbFree(db, pDup);
ExprSetProperty(pExpr, EP_Alias);
}
@@ -349,6 +351,7 @@ static int lookupName(
testcase( iCol==(-1) );
pExpr->iTable = pNC->uNC.pUpsert->regData + iCol;
eNewExprOp = TK_REGISTER;
ExprSetProperty(pExpr, EP_Alias);
}else
#endif /* SQLITE_OMIT_UPSERT */
{
+1 -1
View File
@@ -817,7 +817,7 @@ static void selectExprDefer(
if( pItem->u.x.iOrderByCol==0 ){
Expr *pExpr = pItem->pExpr;
Table *pTab = pExpr->pTab;
if( pExpr->op==TK_COLUMN && pTab && !IsVirtual(pTab)
if( pExpr->op==TK_COLUMN && pExpr->iColumn>=0 && pTab && !IsVirtual(pTab)
&& (pTab->aCol[pExpr->iColumn].colFlags & COLFLAG_SORTERREF)
){
int j;
+99 -45
View File
@@ -3323,6 +3323,7 @@ static char zHelp[] =
".auth ON|OFF Show authorizer callbacks\n"
#endif
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
" Add \"--append\" to open using appendvfs.\n"
".bail on|off Stop after hitting an error. Default OFF\n"
".binary on|off Turn binary output on or off. Default OFF\n"
".cd DIRECTORY Change the working directory to DIRECTORY\n"
@@ -3540,14 +3541,17 @@ static int session_filter(void *pCtx, const char *zTab){
** Otherwise, assume an ordinary database regardless of the filename if
** the type cannot be determined from content.
*/
static int deduceDatabaseType(const char *zName, int dfltZip){
int deduceDatabaseType(const char *zName, int dfltZip){
FILE *f = fopen(zName, "rb");
size_t n;
int rc = SHELL_OPEN_UNSPEC;
char zBuf[100];
if( f==0 ){
if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ) return SHELL_OPEN_ZIPFILE;
return SHELL_OPEN_NORMAL;
if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
return SHELL_OPEN_ZIPFILE;
}else{
return SHELL_OPEN_NORMAL;
}
}
fseek(f, -25, SEEK_END);
n = fread(zBuf, 25, 1, f);
@@ -3560,24 +3564,38 @@ static int deduceDatabaseType(const char *zName, int dfltZip){
&& zBuf[3]==0x06 ){
rc = SHELL_OPEN_ZIPFILE;
}else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){
return SHELL_OPEN_ZIPFILE;
rc = SHELL_OPEN_ZIPFILE;
}
}
fclose(f);
return rc;
}
/* Flags for open_db().
**
** The default behavior of open_db() is to exit(1) if the database fails to
** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error
** but still returns without calling exit.
**
** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a
** ZIP archive if the file does not exist or is empty and its name matches
** the *.zip pattern.
*/
#define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */
#define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */
/*
** Make sure the database is open. If it is not, then open it. If
** the database fails to open, print an error message and exit.
*/
static void open_db(ShellState *p, int keepAlive){
static void open_db(ShellState *p, int openFlags){
if( p->db==0 ){
if( p->openMode==SHELL_OPEN_UNSPEC ){
if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){
p->openMode = SHELL_OPEN_NORMAL;
}else if( access(p->zDbFilename,0)==0 ){
p->openMode = (u8)deduceDatabaseType(p->zDbFilename, 0);
}else{
p->openMode = (u8)deduceDatabaseType(p->zDbFilename,
(openFlags & OPEN_DB_ZIPFILE)!=0);
}
}
switch( p->openMode ){
@@ -3604,7 +3622,7 @@ static void open_db(ShellState *p, int keepAlive){
if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){
utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n",
p->zDbFilename, sqlite3_errmsg(p->db));
if( keepAlive ) return;
if( openFlags & OPEN_DB_KEEPALIVE ) return;
exit(1);
}
#ifndef SQLITE_OMIT_LOAD_EXTENSION
@@ -3638,6 +3656,17 @@ static void open_db(ShellState *p, int keepAlive){
}
}
/*
** Attempt to close the databaes connection. Report errors.
*/
void close_db(sqlite3 *db){
int rc = sqlite3_close(db);
if( rc ){
utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n",
rc, sqlite3_errmsg(db));
}
}
#if HAVE_READLINE || HAVE_EDITLINE
/*
** Readline completion callbacks
@@ -4218,7 +4247,7 @@ static void tryToClone(ShellState *p, const char *zNewDb){
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
}
sqlite3_close(newDb);
close_db(newDb);
}
/*
@@ -4873,6 +4902,7 @@ struct ArCommand {
u8 bZip; /* True if the archive is a ZIP */
u8 bDryRun; /* True if --dry-run */
u8 bAppend; /* True if --append */
u8 fromCmdLine; /* Run from -A instead of .archive */
int nArg; /* Number of command arguments */
char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */
const char *zFile; /* --file argument, or NULL */
@@ -4919,13 +4949,18 @@ static int arUsage(FILE *f){
** Print an error message for the .ar command to stderr and return
** SQLITE_ERROR.
*/
static int arErrorMsg(const char *zFmt, ...){
static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){
va_list ap;
char *z;
va_start(ap, zFmt);
z = sqlite3_vmprintf(zFmt, ap);
va_end(ap);
raw_printf(stderr, "Error: %s (try \".ar --help\")\n", z);
utf8_printf(stderr, "Error: %s\n", z);
if( pAr->fromCmdLine ){
utf8_printf(stderr, "Use \"-A\" for more help\n");
}else{
utf8_printf(stderr, "Use \".archive --help\" for more help\n");
}
sqlite3_free(z);
return SQLITE_ERROR;
}
@@ -4956,7 +4991,7 @@ static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){
case AR_CMD_UPDATE:
case AR_CMD_HELP:
if( pAr->eCmd ){
return arErrorMsg("multiple command options");
return arErrorMsg(pAr, "multiple command options");
}
pAr->eCmd = eSwitch;
break;
@@ -5016,8 +5051,6 @@ static int arParseCommand(
return arUsage(stderr);
}else{
char *z = azArg[1];
memset(pAr, 0, sizeof(ArCommand));
if( z[0]!='-' ){
/* Traditional style [tar] invocation */
int i;
@@ -5029,11 +5062,11 @@ static int arParseCommand(
if( z[i]==pOpt->cShort ) break;
}
if( pOpt==pEnd ){
return arErrorMsg("unrecognized option: %c", z[i]);
return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
}
if( pOpt->bArg ){
if( iArg>=nArg ){
return arErrorMsg("option requires an argument: %c",z[i]);
return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
}
zArg = azArg[iArg++];
}
@@ -5067,7 +5100,7 @@ static int arParseCommand(
if( z[i]==pOpt->cShort ) break;
}
if( pOpt==pEnd ){
return arErrorMsg("unrecognized option: %c\n", z[i]);
return arErrorMsg(pAr, "unrecognized option: %c", z[i]);
}
if( pOpt->bArg ){
if( i<(n-1) ){
@@ -5075,7 +5108,7 @@ static int arParseCommand(
i = n;
}else{
if( iArg>=(nArg-1) ){
return arErrorMsg("option requires an argument: %c\n",z[i]);
return arErrorMsg(pAr, "option requires an argument: %c",z[i]);
}
zArg = azArg[++iArg];
}
@@ -5097,7 +5130,7 @@ static int arParseCommand(
const char *zLong = pOpt->zLong;
if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){
if( pMatch ){
return arErrorMsg("ambiguous option: %s",z);
return arErrorMsg(pAr, "ambiguous option: %s",z);
}else{
pMatch = pOpt;
}
@@ -5105,11 +5138,11 @@ static int arParseCommand(
}
if( pMatch==0 ){
return arErrorMsg("unrecognized option: %s", z);
return arErrorMsg(pAr, "unrecognized option: %s", z);
}
if( pMatch->bArg ){
if( iArg>=(nArg-1) ){
return arErrorMsg("option requires an argument: %s", z);
return arErrorMsg(pAr, "option requires an argument: %s", z);
}
zArg = azArg[++iArg];
}
@@ -5238,6 +5271,7 @@ static int arListCommand(ArCommand *pAr){
}
}
shellFinalize(&rc, pSql);
sqlite3_free(zWhere);
return rc;
}
@@ -5440,12 +5474,14 @@ end_ar_transaction:
*/
static int arDotCommand(
ShellState *pState, /* Current shell tool state */
int fromCmdLine, /* True if -A command-line option, not .ar cmd */
char **azArg, /* Array of arguments passed to dot command */
int nArg /* Number of entries in azArg[] */
){
ArCommand cmd;
int rc;
memset(&cmd, 0, sizeof(cmd));
cmd.fromCmdLine = fromCmdLine;
rc = arParseCommand(azArg, nArg, &cmd);
if( rc==SQLITE_OK ){
int eDbType = SHELL_OPEN_UNSPEC;
@@ -5492,7 +5528,7 @@ static int arDotCommand(
shellPutsFunc, 0, 0);
}
if( cmd.zSrcTable==0 && cmd.bZip==0 ){
if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){
if( cmd.eCmd!=AR_CMD_CREATE
&& sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0)
){
@@ -5528,7 +5564,7 @@ static int arDotCommand(
}
end_ar_command:
if( cmd.db!=pState->db ){
sqlite3_close(cmd.db);
close_db(cmd.db);
}
sqlite3_free(cmd.zSrcTable);
@@ -5608,7 +5644,7 @@ static int do_meta_command(char *zLine, ShellState *p){
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){
open_db(p, 0);
rc = arDotCommand(p, azArg, nArg);
rc = arDotCommand(p, 0, azArg, nArg);
}else
#endif
@@ -5620,11 +5656,14 @@ static int do_meta_command(char *zLine, ShellState *p){
sqlite3 *pDest;
sqlite3_backup *pBackup;
int j;
const char *zVfs = 0;
for(j=1; j<nArg; j++){
const char *z = azArg[j];
if( z[0]=='-' ){
while( z[0]=='-' ) z++;
/* No options to process at this time */
if( z[1]=='-' ) z++;
if( strcmp(z, "-append")==0 ){
zVfs = "apndvfs";
}else
{
utf8_printf(stderr, "unknown option: %s\n", azArg[j]);
return 1;
@@ -5635,7 +5674,7 @@ static int do_meta_command(char *zLine, ShellState *p){
zDb = zDestFile;
zDestFile = azArg[j];
}else{
raw_printf(stderr, "too many arguments to .backup\n");
raw_printf(stderr, "Usage: .backup ?DB? ?--append? FILENAME\n");
return 1;
}
}
@@ -5644,17 +5683,18 @@ static int do_meta_command(char *zLine, ShellState *p){
return 1;
}
if( zDb==0 ) zDb = "main";
rc = sqlite3_open(zDestFile, &pDest);
rc = sqlite3_open_v2(zDestFile, &pDest,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs);
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
sqlite3_close(pDest);
close_db(pDest);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
if( pBackup==0 ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
sqlite3_close(pDest);
close_db(pDest);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
@@ -5665,7 +5705,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
rc = 1;
}
sqlite3_close(pDest);
close_db(pDest);
}else
if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){
@@ -6481,7 +6521,7 @@ static int do_meta_command(char *zLine, ShellState *p){
int newFlag = 0; /* True to delete file before opening */
/* Close the existing database */
session_close_all(p);
sqlite3_close(p->db);
close_db(p->db);
p->db = 0;
p->zDbFilename = 0;
sqlite3_free(p->zFreeOnClose);
@@ -6511,7 +6551,7 @@ static int do_meta_command(char *zLine, ShellState *p){
if( zNewFilename ){
if( newFlag ) shellDeleteFile(zNewFilename);
p->zDbFilename = zNewFilename;
open_db(p, 1);
open_db(p, OPEN_DB_KEEPALIVE);
if( p->db==0 ){
utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename);
sqlite3_free(zNewFilename);
@@ -6661,14 +6701,14 @@ static int do_meta_command(char *zLine, ShellState *p){
rc = sqlite3_open(zSrcFile, &pSrc);
if( rc!=SQLITE_OK ){
utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
sqlite3_close(pSrc);
close_db(pSrc);
return 1;
}
open_db(p, 0);
pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
if( pBackup==0 ){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
sqlite3_close(pSrc);
close_db(pSrc);
return 1;
}
while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
@@ -6688,7 +6728,7 @@ static int do_meta_command(char *zLine, ShellState *p){
utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
rc = 1;
}
sqlite3_close(pSrc);
close_db(pSrc);
}else
if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){
@@ -7372,7 +7412,10 @@ static int do_meta_command(char *zLine, ShellState *p){
initText(&s);
open_db(p, 0);
rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0);
if( rc ) return shellDatabaseError(p->db);
if( rc ){
sqlite3_finalize(pStmt);
return shellDatabaseError(p->db);
}
if( nArg>2 && c=='i' ){
/* It is an historical accident that the .indexes command shows an error
@@ -7380,6 +7423,7 @@ static int do_meta_command(char *zLine, ShellState *p){
** command does not. */
raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n");
rc = 1;
sqlite3_finalize(pStmt);
goto meta_command_exit;
}
for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){
@@ -8199,7 +8243,7 @@ static void usage(int showDetail){
*/
static void verify_uninitialized(void){
if( sqlite3_config(-1)==SQLITE_MISUSE ){
utf8_printf(stdout, "WARNING: attempt to configuration SQLite after"
utf8_printf(stdout, "WARNING: attempt to configure SQLite after"
" initialization.\n");
}
}
@@ -8280,6 +8324,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
int nCmd = 0;
char **azCmd = 0;
const char *zVfs = 0; /* Value of -vfs command-line option */
#if !SQLITE_SHELL_IS_UTF8
char **argvToFree = 0;
int argcToFree = 0;
#endif
setBinaryMode(stdin, 0);
setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */
@@ -8303,7 +8351,9 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
*/
#if !SQLITE_SHELL_IS_UTF8
sqlite3_initialize();
argv = malloc(sizeof(argv[0])*argc);
argvToFree = malloc(sizeof(argv[0])*argc*2);
argcToFree = argc;
argv = argvToFree + argc;
if( argv==0 ) shell_out_of_memory();
for(i=0; i<argc; i++){
char *z = sqlite3_win32_unicode_to_utf8(wargv[i]);
@@ -8313,6 +8363,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
argv[i] = malloc( n+1 );
if( argv[i]==0 ) shell_out_of_memory();
memcpy(argv[i], z, n+1);
argvToFree[i] = argv[i];
sqlite3_free(z);
}
sqlite3_shutdown();
@@ -8634,12 +8685,12 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
" with \"%s\"\n", z);
return 1;
}
open_db(&data, 0);
open_db(&data, OPEN_DB_ZIPFILE);
if( z[2] ){
argv[i] = &z[2];
arDotCommand(&data, argv+(i-1), argc-(i-1));
arDotCommand(&data, 1, argv+(i-1), argc-(i-1));
}else{
arDotCommand(&data, argv+i, argc-i);
arDotCommand(&data, 1, argv+i, argc-i);
}
readStdin = 0;
break;
@@ -8718,7 +8769,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
set_table_name(&data, 0);
if( data.db ){
session_close_all(&data);
sqlite3_close(data.db);
close_db(data.db);
}
sqlite3_free(data.zFreeOnClose);
find_home_dir(1);
@@ -8726,8 +8777,11 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){
data.doXdgOpen = 0;
clearTempFile(&data);
#if !SQLITE_SHELL_IS_UTF8
for(i=0; i<argc; i++) free(argv[i]);
free(argv);
for(i=0; i<argcToFree; i++) free(argvToFree[i]);
free(argvToFree);
#endif
/* Clear the global data structure so that valgrind will detect memory
** leaks */
memset(&data, 0, sizeof(data));
return rc;
}
+21 -7
View File
@@ -504,6 +504,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
@@ -511,6 +512,7 @@ int sqlite3_exec(
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
@@ -6292,6 +6294,10 @@ struct sqlite3_index_info {
/*
** CAPI3REF: Virtual Table Scan Flags
**
** Virtual table implementations are allowed to set the
** [sqlite3_index_info].idxFlags field to some combination of
** these bits.
*/
#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */
@@ -7155,12 +7161,20 @@ typedef struct sqlite3_str sqlite3_str;
** CONSTRUCTOR: sqlite3_str
**
** ^The [sqlite3_str_new(D)] interface allocates and initializes
** a new [sqlite3_str]
** object. ^The [sqlite3_str_new()] interface returns NULL on an out-of-memory
** condition. To avoid memory leaks, the object returned by
** a new [sqlite3_str] object. To avoid memory leaks, the object returned by
** [sqlite3_str_new()] must be freed by a subsequent call to
** [sqlite3_str_finish(X)].
**
** ^The [sqlite3_str_new(D)] interface always returns a pointer to a
** valid [sqlite3_str] object, though in the event of an out-of-memory
** error the returned object might be a special singleton that will
** silently reject new text, always return SQLITE_NOMEM from
** [sqlite3_str_errcode()], always return 0 for
** [sqlite3_str_length()], and always return NULL from
** [sqlite3_str_finish(X)]. It is always safe to use the value
** returned by [sqlite3_str_new(D)] as the sqlite3_str parameter
** to any of the other [sqlite3_str] methods.
**
** The D parameter to [sqlite3_str_new(D)] may be NULL. If the
** D parameter in [sqlite3_str_new(D)] is not NULL, then the maximum
** length of the string contained in the [sqlite3_str] object will be
@@ -8525,11 +8539,11 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
** method of a [virtual table], then it returns true if and only if the
** column is being fetched as part of an UPDATE operation during which the
** column value will not change. Applications might use this to substitute
** a lighter-weight value to return that the corresponding [xUpdate] method
** understands as a "no-change" value.
** a return value that is less expensive to compute and that the corresponding
** [xUpdate] method understands as a "no-change" value.
**
** If the [xColumn] method calls sqlite3_vtab_nochange() and finds that
** the column is not changed by the UPDATE statement, they the xColumn
** the column is not changed by the UPDATE statement, then the xColumn
** method can optionally return without setting a result, without calling
** any of the [sqlite3_result_int|sqlite3_result_xxxxx() interfaces].
** In that case, [sqlite3_value_nochange(X)] will return true for the
@@ -9024,7 +9038,7 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
** been a prior call to [sqlite3_deserialize(D,S,...)] with the same
** values of D and S.
** The size of the database is written into *P even if the
** SQLITE_SERIALIZE_NOCOPY bit is set but no contigious copy
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
+1 -1
View File
@@ -4166,6 +4166,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*),
FuncDestructor *pDestructor
);
void sqlite3NoopDestructor(void*);
void sqlite3OomFault(sqlite3*);
void sqlite3OomClear(sqlite3*);
int sqlite3ApiExit(sqlite3 *db, int);
@@ -4268,7 +4269,6 @@ int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, VTable *);
FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
+18
View File
@@ -32,6 +32,8 @@ static struct MemFault {
int nRepeat; /* Number of times to repeat the failure */
int nBenign; /* Number of benign failures seen since last config */
int nFail; /* Number of failures seen since last config */
int nOkBefore; /* Successful allocations prior to the first fault */
int nOkAfter; /* Successful allocations after a fault */
u8 enable; /* True if enabled */
int isInstalled; /* True if the fault simulation layer is installed */
int isBenignMode; /* True if malloc failures are considered benign */
@@ -47,18 +49,32 @@ static void sqlite3Fault(void){
cnt++;
}
/*
** This routine exists as a place to set a breakpoint that will
** fire the first time any malloc() fails on a single test case.
** The sqlite3Fault() routine above runs on every malloc() failure.
** This routine only runs on the first such failure.
*/
static void sqlite3FirstFault(void){
static int cnt2 = 0;
cnt2++;
}
/*
** Check to see if a fault should be simulated. Return true to simulate
** the fault. Return false if the fault should not be simulated.
*/
static int faultsimStep(void){
if( likely(!memfault.enable) ){
memfault.nOkAfter++;
return 0;
}
if( memfault.iCountdown>0 ){
memfault.iCountdown--;
memfault.nOkBefore++;
return 0;
}
if( memfault.nFail==0 ) sqlite3FirstFault();
sqlite3Fault();
memfault.nFail++;
if( memfault.isBenignMode>0 ){
@@ -133,6 +149,8 @@ static void faultsimConfig(int nDelay, int nRepeat){
memfault.nRepeat = nRepeat;
memfault.nBenign = 0;
memfault.nFail = 0;
memfault.nOkBefore = 0;
memfault.nOkAfter = 0;
memfault.enable = nDelay>=0;
/* Sometimes, when running multi-threaded tests, the isBenignMode
+9 -5
View File
@@ -845,7 +845,7 @@ static void updateVirtualTable(
int regRowid; /* Register for ephem table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
int bOnePass; /* True to use onepass strategy */
int eOnePass; /* True to use onepass strategy */
int addr; /* Address of OP_OpenEphemeral */
/* Allocate nArg registers in which to gather the arguments for VUpdate. Then
@@ -890,12 +890,16 @@ static void updateVirtualTable(
sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
}
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
eOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);
if( bOnePass ){
/* There is no ONEPASS_MULTI on virtual tables */
assert( eOnePass==ONEPASS_OFF || eOnePass==ONEPASS_SINGLE );
if( eOnePass ){
/* If using the onepass strategy, no-op out the OP_OpenEphemeral coded
** above. */
sqlite3VdbeChangeToNoop(v, addr);
sqlite3VdbeAddOp1(v, OP_Close, iCsr);
}else{
/* Create a record from the argument register contents and insert it into
** the ephemeral table. */
@@ -911,7 +915,7 @@ static void updateVirtualTable(
}
if( bOnePass==0 ){
if( eOnePass==ONEPASS_OFF ){
/* End the virtual table scan */
sqlite3WhereEnd(pWInfo);
@@ -931,7 +935,7 @@ static void updateVirtualTable(
/* End of the ephemeral table scan. Or, if using the onepass strategy,
** jump to here if the scan visited zero rows. */
if( bOnePass==0 ){
if( eOnePass==ONEPASS_OFF ){
sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); VdbeCoverage(v);
sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0);
+1
View File
@@ -229,6 +229,7 @@ void sqlite3UpsertDoUpdate(
VdbeComment((v, "%s.%s", pIdx->zName,
pTab->aCol[pPk->aiColumn[i]].zName));
}
sqlite3VdbeVerifyAbortable(v, OE_Abort);
i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
VdbeCoverage(v);
sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0,
+43 -9
View File
@@ -915,6 +915,9 @@ case OP_Yield: { /* in1, jump */
*/
case OP_HaltIfNull: { /* in3 */
pIn3 = &aMem[pOp->p3];
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
if( (pIn3->flags & MEM_Null)==0 ) break;
/* Fall through into OP_Halt */
}
@@ -954,6 +957,9 @@ case OP_Halt: {
int pcx;
pcx = (int)(pOp - aOp);
#ifdef SQLITE_DEBUG
if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
if( pOp->p1==SQLITE_OK && p->pFrame ){
/* Halt the sub-program. Return control to the parent frame. */
pFrame = p->pFrame;
@@ -3324,6 +3330,8 @@ case OP_ReadCookie: { /* out2 */
*/
case OP_SetCookie: {
Db *pDb;
sqlite3VdbeIncrWriteCounter(p, 0);
assert( pOp->p2<SQLITE_N_BTREE_META );
assert( pOp->p1>=0 && pOp->p1<db->nDb );
assert( DbMaskTest(p->btreeMask, pOp->p1) );
@@ -4287,11 +4295,8 @@ case OP_NewRowid: { /* out2 */
pOut = out2Prerelease(p, pOp);
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
if( !pC->isTable ){
rc = SQLITE_CORRUPT_BKPT;
goto abort_due_to_error;
}
assert( pC!=0 );
assert( pC->isTable );
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
{
@@ -4460,6 +4465,7 @@ case OP_InsertInt: {
assert( (pOp->p5 & OPFLAG_ISNOOP) || pC->isTable );
assert( pOp->p4type==P4_TABLE || pOp->p4type>=P4_STATIC );
REGISTER_TRACE(pOp->p2, pData);
sqlite3VdbeIncrWriteCounter(p, pC);
if( pOp->opcode==OP_Insert ){
pKey = &aMem[pOp->p3];
@@ -4574,6 +4580,7 @@ case OP_Delete: {
assert( pC->eCurType==CURTYPE_BTREE );
assert( pC->uc.pCursor!=0 );
assert( pC->deferredMoveto==0 );
sqlite3VdbeIncrWriteCounter(p, pC);
#ifdef SQLITE_DEBUG
if( pOp->p4type==P4_TABLE && HasRowid(pOp->p4.pTab) && pOp->p5==0 ){
@@ -4742,10 +4749,10 @@ case OP_SorterData: {
** If the P1 cursor must be pointing to a valid row (not a NULL row)
** of a real table, not a pseudo-table.
**
** If P3!=0 then this opcode is allowed to make an ephermeral pointer
** If P3!=0 then this opcode is allowed to make an ephemeral pointer
** into the database page. That means that the content of the output
** register will be invalidated as soon as the cursor moves - including
** moves caused by other cursors that "save" the the current cursors
** moves caused by other cursors that "save" the current cursors
** position in order that they can write to the same table. If P3==0
** then a copy of the data is made into memory. P3!=0 is faster, but
** P3==0 is safer.
@@ -5192,6 +5199,7 @@ case OP_IdxInsert: { /* in2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
sqlite3VdbeIncrWriteCounter(p, pC);
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
@@ -5238,6 +5246,7 @@ case OP_IdxDelete: {
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->eCurType==CURTYPE_BTREE );
sqlite3VdbeIncrWriteCounter(p, pC);
pCrsr = pC->uc.pCursor;
assert( pCrsr!=0 );
assert( pOp->p5==0 );
@@ -5460,6 +5469,7 @@ case OP_Destroy: { /* out2 */
int iMoved;
int iDb;
sqlite3VdbeIncrWriteCounter(p, 0);
assert( p->readOnly==0 );
assert( pOp->p1>1 );
pOut = out2Prerelease(p, pOp);
@@ -5509,6 +5519,7 @@ case OP_Destroy: { /* out2 */
case OP_Clear: {
int nChange;
sqlite3VdbeIncrWriteCounter(p, 0);
nChange = 0;
assert( p->readOnly==0 );
assert( DbMaskTest(p->btreeMask, pOp->p2) );
@@ -5558,13 +5569,14 @@ case OP_ResetSorter: {
** Allocate a new b-tree in the main database file if P1==0 or in the
** TEMP database file if P1==1 or in an attached database if
** P1>1. The P3 argument must be 1 (BTREE_INTKEY) for a rowid table
** it must be 2 (BTREE_BLOBKEY) for a index or WITHOUT ROWID table.
** it must be 2 (BTREE_BLOBKEY) for an index or WITHOUT ROWID table.
** The root page number of the new b-tree is stored in register P2.
*/
case OP_CreateBtree: { /* out2 */
int pgno;
Db *pDb;
sqlite3VdbeIncrWriteCounter(p, 0);
pOut = out2Prerelease(p, pOp);
pgno = 0;
assert( pOp->p3==BTREE_INTKEY || pOp->p3==BTREE_BLOBKEY );
@@ -5584,6 +5596,7 @@ case OP_CreateBtree: { /* out2 */
** Run the SQL statement or statements specified in the P4 string.
*/
case OP_SqlExec: {
sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
db->nSqlExec--;
@@ -5673,6 +5686,7 @@ case OP_LoadAnalysis: {
** schema consistent with what is on disk.
*/
case OP_DropTable: {
sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteTable(db, pOp->p1, pOp->p4.z);
break;
}
@@ -5686,6 +5700,7 @@ case OP_DropTable: {
** schema consistent with what is on disk.
*/
case OP_DropIndex: {
sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteIndex(db, pOp->p1, pOp->p4.z);
break;
}
@@ -5699,6 +5714,7 @@ case OP_DropIndex: {
** schema consistent with what is on disk.
*/
case OP_DropTrigger: {
sqlite3VdbeIncrWriteCounter(p, 0);
sqlite3UnlinkAndDeleteTrigger(db, pOp->p1, pOp->p4.z);
break;
}
@@ -6745,7 +6761,7 @@ case OP_VFilter: { /* jump */
** If the VColumn opcode is being used to fetch the value of
** an unchanging column during an UPDATE operation, then the P5
** value is 1. Otherwise, P5 is 0. The P5 value is returned
** by sqlite3_vtab_nochange() routine can can be used
** by sqlite3_vtab_nochange() routine and can be used
** by virtual table implementations to return special "no-change"
** marks which can be more efficient, depending on the virtual table.
*/
@@ -6908,6 +6924,7 @@ case OP_VUpdate: {
|| pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
);
assert( p->readOnly==0 );
sqlite3VdbeIncrWriteCounter(p, 0);
pVtab = pOp->p4.pVtab->pVtab;
if( pVtab==0 || NEVER(pVtab->pModule==0) ){
rc = SQLITE_LOCKED;
@@ -7225,6 +7242,22 @@ case OP_CursorHint: {
}
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
#ifdef SQLITE_DEBUG
/* Opcode: Abortable * * * * *
**
** Verify that an Abort can happen. Assert if an Abort at this point
** might cause database corruption. This opcode only appears in debugging
** builds.
**
** An Abort is safe if either there have been no writes, or if there is
** an active statement journal.
*/
case OP_Abortable: {
sqlite3VdbeAssertAbortable(p);
break;
}
#endif
/* Opcode: Noop * * * * *
**
** Do nothing. This instruction is often useful as a jump
@@ -7236,8 +7269,9 @@ case OP_CursorHint: {
** This opcode records information from the optimizer. It is the
** the same as a no-op. This opcodesnever appears in a real VM program.
*/
default: { /* This is really OP_Noop and OP_Explain */
default: { /* This is really OP_Noop, OP_Explain */
assert( pOp->opcode==OP_Noop || pOp->opcode==OP_Explain );
break;
}
+5
View File
@@ -197,6 +197,11 @@ void sqlite3VdbeEndCoroutine(Vdbe*,int);
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
# define sqlite3VdbeVerifyNoResultRow(A)
#endif
#if defined(SQLITE_DEBUG)
void sqlite3VdbeVerifyAbortable(Vdbe *p, int);
#else
# define sqlite3VdbeVerifyAbortable(A,B)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno);
#ifndef SQLITE_OMIT_EXPLAIN
void sqlite3VdbeExplain(Parse*,u8,const char*,...);
+9
View File
@@ -379,6 +379,7 @@ struct Vdbe {
int nOp; /* Number of instructions in the program */
#ifdef SQLITE_DEBUG
int rcApp; /* errcode set by sqlite3_result_error_code() */
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
u8 errorAction; /* Recovery action to do in case of an error */
@@ -514,6 +515,14 @@ int sqlite3VdbeSorterRewind(const VdbeCursor *, int *);
int sqlite3VdbeSorterWrite(const VdbeCursor *, Mem *);
int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *);
#ifdef SQLITE_DEBUG
void sqlite3VdbeIncrWriteCounter(Vdbe*, VdbeCursor*);
void sqlite3VdbeAssertAbortable(Vdbe*);
#else
# define sqlite3VdbeIncrWriteCounter(V,C)
# define sqlite3VdbeAssertAbortable(V)
#endif
#if !defined(SQLITE_OMIT_SHARED_CACHE)
void sqlite3VdbeEnter(Vdbe*);
#else
-22
View File
@@ -787,28 +787,6 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context *p){
return *piTime;
}
/*
** The following is the implementation of an SQL function that always
** fails with an error message stating that the function is used in the
** wrong context. The sqlite3_overload_function() API might construct
** SQL function that use this routine so that the functions will exist
** for name resolution but are actually overloaded by the xFindFunction
** method of virtual tables.
*/
void sqlite3InvalidFunction(
sqlite3_context *context, /* The function calling context */
int NotUsed, /* Number of arguments to the function */
sqlite3_value **NotUsed2 /* Value of each argument */
){
const char *zName = context->pFunc->zName;
char *zErr;
UNUSED_PARAMETER2(NotUsed, NotUsed2);
zErr = sqlite3_mprintf(
"unable to use function %s in the requested context", zName);
sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr);
}
/*
** Create a new aggregate context for p and return a pointer to
** its pMem->z element.
+42 -5
View File
@@ -603,6 +603,32 @@ int sqlite3VdbeAssertMayAbort(Vdbe *v, int mayAbort){
}
#endif /* SQLITE_DEBUG - the sqlite3AssertMayAbort() function */
#ifdef SQLITE_DEBUG
/*
** Increment the nWrite counter in the VDBE if the cursor is not an
** ephemeral cursor, or if the cursor argument is NULL.
*/
void sqlite3VdbeIncrWriteCounter(Vdbe *p, VdbeCursor *pC){
if( pC==0
|| (pC->eCurType!=CURTYPE_SORTER
&& pC->eCurType!=CURTYPE_PSEUDO
&& !pC->isEphemeral)
){
p->nWrite++;
}
}
#endif
#ifdef SQLITE_DEBUG
/*
** Assert if an Abort at this point in time might result in a corrupt
** database.
*/
void sqlite3VdbeAssertAbortable(Vdbe *p){
assert( p->nWrite==0 || p->usesStmtJournal );
}
#endif
/*
** This routine is called after all opcodes have been inserted. It loops
** through all the opcodes and fixes up some details.
@@ -762,6 +788,17 @@ void sqlite3VdbeVerifyNoResultRow(Vdbe *p){
}
#endif
/*
** Generate code (a single OP_Abortable opcode) that will
** verify that the VDBE program can safely call Abort in the current
** context.
*/
#if defined(SQLITE_DEBUG)
void sqlite3VdbeVerifyAbortable(Vdbe *p, int onError){
if( onError==OE_Abort ) sqlite3VdbeAddOp0(p, OP_Abortable);
}
#endif
/*
** This function returns a pointer to the array of opcodes associated with
** the Vdbe passed as the first argument. It is the callers responsibility
@@ -2995,6 +3032,9 @@ int sqlite3VdbeReset(Vdbe *p){
sqlite3DbFree(db, p->zErrMsg);
p->zErrMsg = 0;
p->pResultSet = 0;
#ifdef SQLITE_DEBUG
p->nWrite = 0;
#endif
/* Save profiling information from this VDBE run.
*/
@@ -3917,13 +3957,10 @@ static int sqlite3IntFloatCompare(i64 i, double r){
i64 y;
double s;
if( r<-9223372036854775808.0 ) return +1;
if( r>9223372036854775807.0 ) return -1;
if( r>=9223372036854775808.0 ) return -1;
y = (i64)r;
if( i<y ) return -1;
if( i>y ){
if( y==SMALLEST_INT64 && r>0.0 ) return -1;
return +1;
}
if( i>y ) return +1;
s = (double)i;
if( s<r ) return -1;
if( s>r ) return +1;
+1 -1
View File
@@ -800,7 +800,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
/* A no-op destructor */
static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
/*
** Set the value stored in *pMem should already be a NULL.
+13 -10
View File
@@ -1049,9 +1049,6 @@ FuncDef *sqlite3VtabOverloadFunction(
void *pArg = 0;
FuncDef *pNew;
int rc = 0;
char *zLowerName;
unsigned char *z;
/* Check to see the left operand is a column in a virtual table */
if( NEVER(pExpr==0) ) return pDef;
@@ -1066,16 +1063,22 @@ FuncDef *sqlite3VtabOverloadFunction(
if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFindFunction method on the virtual table implementation
** to see if the implementation wants to overload this function
** to see if the implementation wants to overload this function.
**
** Though undocumented, we have historically always invoked xFindFunction
** with an all lower-case function name. Continue in this tradition to
** avoid any chance of an incompatibility.
*/
zLowerName = sqlite3DbStrDup(db, pDef->zName);
if( zLowerName ){
for(z=(unsigned char*)zLowerName; *z; z++){
*z = sqlite3UpperToLower[*z];
#ifdef SQLITE_DEBUG
{
int i;
for(i=0; pDef->zName[i]; i++){
unsigned char x = (unsigned char)pDef->zName[i];
assert( x==sqlite3UpperToLower[x] );
}
rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xSFunc, &pArg);
sqlite3DbFree(db, zLowerName);
}
#endif
rc = pMod->xFindFunction(pVtab, nArg, pDef->zName, &xSFunc, &pArg);
if( rc==0 ){
return pDef;
}
+10 -5
View File
@@ -2862,14 +2862,16 @@ static int whereLoopAddBtree(
/* TUNING: One-time cost for computing the automatic index is
** estimated to be X*N*log2(N) where N is the number of rows in
** the table being indexed and where X is 7 (LogEst=28) for normal
** tables or 1.375 (LogEst=4) for views and subqueries. The value
** tables or 0.5 (LogEst=-10) for views and subqueries. The value
** of X is smaller for views and subqueries so that the query planner
** will be more aggressive about generating automatic indexes for
** those objects, since there is no opportunity to add schema
** indexes on subqueries and views. */
pNew->rSetup = rLogSize + rSize + 4;
pNew->rSetup = rLogSize + rSize;
if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){
pNew->rSetup += 24;
pNew->rSetup += 28;
}else{
pNew->rSetup -= 10;
}
ApplyCostMultiplier(pNew->rSetup, pTab->costMult);
if( pNew->rSetup<0 ) pNew->rSetup = 0;
@@ -4005,12 +4007,15 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue;
if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){
if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<3 ){
/* Do not use an automatic index if the this loop is expected
** to run less than 2 times. */
** to run less than 1.25 times. It is tempting to also exclude
** automatic index usage on an outer loop, but sometimes an automatic
** index is useful in the outer loop of a correlated subquery. */
assert( 10==sqlite3LogEst(2) );
continue;
}
/* At this point, pWLoop is a candidate to be the next loop.
** Compute its cost */
rUnsorted = sqlite3LogEstAdd(pWLoop->rSetup,pWLoop->rRun + pFrom->nRow);
+165
View File
@@ -25,6 +25,11 @@ ifcapable {!autoinc} {
return
}
if {[permutation]=="inmemory_journal"} {
finish_test
return
}
sqlite3_db_config_lookaside db 0 0 0
# The database is initially empty.
@@ -684,4 +689,164 @@ do_execsql_test autoinc-11.1 {
SELECT seq FROM sqlite_sequence WHERE name='t11';
} {5}
# 2018-05-23 ticket d8dc2b3a58cd5dc2918a1d4acbba4676a23ada4c
# Does not crash if the sqlite_sequence table schema is missing
# or corrupt.
#
do_test autoinc-12.1 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE fake_sequence(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql=replace(sql,'fake_','sqlite_'),
name='sqlite_sequence',
tbl_name='sqlite_sequence'
WHERE name='fake_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.2 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql=replace(sql,'sqlite_','x_'),
name='x_sequence',
tbl_name='x_sequence'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
ifcapable vtab {
set err "database disk image is malformed"
} else {
set err {malformed database schema (sqlite_sequence) - near "VIRTUAL": syntax error}
}
do_test autoinc-12.3 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE VIRTUAL TABLE sqlite_sequence USING sqlite_dbpage'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} [list 1 $err]
do_test autoinc-12.4 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
CREATE TABLE fake(name TEXT PRIMARY KEY,seq) WITHOUT ROWID;
}
set root1 [db one {SELECT rootpage FROM sqlite_master
WHERE name='sqlite_sequence'}]
set root2 [db one {SELECT rootpage FROM sqlite_master
WHERE name='fake'}]
db eval {
PRAGMA writable_schema=on;
UPDATE sqlite_master SET rootpage=$root2
WHERE name='sqlite_sequence';
UPDATE sqlite_master SET rootpage=$root1
WHERE name='fake';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
breakpoint
do_test autoinc-12.5 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(x)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two');
}} msg]
lappend res $msg
} {1 {database disk image is malformed}}
do_test autoinc-12.6 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(x,y INTEGER PRIMARY KEY)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two'),('three'),('four');
INSERT INTO t1(b) VALUES('five');
PRAGMA integrity_check;
}} msg]
lappend res $msg
} {0 ok}
do_test autoinc-12.7 {
db close
forcedelete test.db
sqlite3 db test.db
db eval {
CREATE TABLE t1(a INTEGER PRIMARY KEY AUTOINCREMENT, b TEXT);
INSERT INTO t1(b) VALUES('one');
PRAGMA writable_schema=on;
UPDATE sqlite_master SET
sql='CREATE TABLE sqlite_sequence(y INTEGER PRIMARY KEY,x)'
WHERE name='sqlite_sequence';
}
db close
sqlite3 db test.db
set res [catch {db eval {
INSERT INTO t1(b) VALUES('two'),('three'),('four');
INSERT INTO t1(b) VALUES('five');
PRAGMA integrity_check;
}} msg]
lappend res $msg
} {0 ok}
finish_test
+9
View File
@@ -148,4 +148,13 @@ do_catchsql_test 4.3 {
USING csv(filename='FileDoesNotExist.csv');
} {1 {cannot open 'FileDoesNotExist.csv' for reading}}
# 2018-06-02
# Problem with single-column CSV support reported on the mailing list
# by Trent W. Buck.
#
do_execsql_test 4.4 {
CREATE VIRTUAL TABLE temp.trent USING csv(data='1');
SELECT * FROM trent;
} {1}
finish_test
+31 -15
View File
@@ -24,7 +24,24 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
proc eqp {sql {db db}} { uplevel execsql [list "EXPLAIN QUERY PLAN $sql"] $db }
proc eqp {sql {db db}} {
uplevel [subst -nocommands {
set eqpres [list]
$db eval "$sql" {
lappend eqpres [set detail]
}
set eqpres
}]
}
proc do_detail_test {tn sql res} {
set normalres [list {*}$res]
uplevel [subst -nocommands {
do_test $tn {
eqp { $sql }
} {$normalres}
}]
}
###########################################################################
### SECTION 2: Enabling Foreign Key Support
@@ -970,20 +987,20 @@ do_test e_fkey-25.1 {
);
}
} {}
do_execsql_test e_fkey-25.2 {
do_detail_test e_fkey-25.2 {
PRAGMA foreign_keys = OFF;
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
EXPLAIN QUERY PLAN SELECT rowid FROM track WHERE trackartist = ?;
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SCAN TABLE track}
{SCAN TABLE artist}
{SCAN TABLE track}
}
do_execsql_test e_fkey-25.3 {
do_detail_test e_fkey-25.3 {
PRAGMA foreign_keys = ON;
EXPLAIN QUERY PLAN DELETE FROM artist WHERE 1;
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SCAN TABLE track}
{SCAN TABLE artist}
{SCAN TABLE track}
}
do_test e_fkey-25.4 {
execsql {
@@ -1097,21 +1114,20 @@ do_test e_fkey-27.1 {
do_test e_fkey-27.2 {
eqp { INSERT INTO artist VALUES(?, ?) }
} {}
do_execsql_test e_fkey-27.3 {
do_detail_test e_fkey-27.3 {
EXPLAIN QUERY PLAN UPDATE artist SET artistid = ?, artistname = ?
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SCAN TABLE artist}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
}
do_execsql_test e_fkey-27.4 {
do_detail_test e_fkey-27.4 {
EXPLAIN QUERY PLAN DELETE FROM artist
} {
0 0 0 {SCAN TABLE artist}
0 0 0 {SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
{SCAN TABLE artist}
{SEARCH TABLE track USING COVERING INDEX trackindex (trackartist=?)}
}
###########################################################################
### SECTION 4.1: Composite Foreign Key Constraints
###########################################################################
+30
View File
@@ -784,5 +784,35 @@ do_execsql_test json-13.110 {
WHERE Z.value==t2.id);
} {3 {{"value":3}} 1 {{"items":[3,5]}} 5 {{"value":5}} 1 {{"items":[3,5]}}}
# 2018-05-16
# Incorrect fullkey output from json_each()
# when the input JSON is not an array or object.
#
do_execsql_test json-14.100 {
SELECT fullkey FROM json_each('123');
} {$}
do_execsql_test json-14.110 {
SELECT fullkey FROM json_each('123.56');
} {$}
do_execsql_test json-14.120 {
SELECT fullkey FROM json_each('"hello"');
} {$}
do_execsql_test json-14.130 {
SELECT fullkey FROM json_each('null');
} {$}
do_execsql_test json-14.140 {
SELECT fullkey FROM json_tree('123');
} {$}
do_execsql_test json-14.150 {
SELECT fullkey FROM json_tree('123.56');
} {$}
do_execsql_test json-14.160 {
SELECT fullkey FROM json_tree('"hello"');
} {$}
do_execsql_test json-14.170 {
SELECT fullkey FROM json_tree('null');
} {$}
finish_test
+5 -2
View File
@@ -174,8 +174,11 @@ do_test malloc5-2.2 {
execsql {
COMMIT;
}
list $nRelease $data
} [list $pgalloc [list 1 2 3 4 5 6]]
value_in_range $::pgalloc $::mrange $nRelease
} [value_in_range $::pgalloc $::mrange]
do_test malloc5-2.2.1 {
set data
} {1 2 3 4 5 6}
do_test malloc5-3.1 {
# Simple test to show that if two pagers are opened from within this
+19 -14
View File
@@ -270,22 +270,27 @@ forcedelete test.db-journal
sqlite3 db test.db
ifcapable explain {
do_execsql_test misc7-14.1 {
do_execsql_test misc7-14.0 {
CREATE TABLE abc(a PRIMARY KEY, b, c);
EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1;
}
do_eqp_test misc7-14.1 {
SELECT * FROM abc AS t2 WHERE rowid = 1;
} {
0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?)}
}
do_execsql_test misc7-14.2 {
EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1;
} {0 0 0
{SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?)}
}
do_execsql_test misc7-14.3 {
EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a;
} {0 0 0
{SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1}
}
QUERY PLAN
`--SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?)
}
do_eqp_test misc7-14.2 {
SELECT * FROM abc AS t2 WHERE a = 1;
} {
QUERY PLAN
`--SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?)
}
do_eqp_test misc7-14.3 {
SELECT * FROM abc AS t2 ORDER BY a;
} {
QUERY PLAN
`--SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1
}
}
db close
+2 -2
View File
@@ -55,11 +55,11 @@ if {![clang_sanitize_address]} {
do_test 1.1.1 {
set ::log [list]
list [catch {
for {set i 0} {$i < 2000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
for {set i 0} {$i < 20000} {incr i} { sqlite3 dbh_$i test.db -readonly 1 }
} msg] $msg
} {1 {unable to open database file}}
do_test 1.1.2 {
catch { for {set i 0} {$i < 2000} {incr i} { dbh_$i close } }
catch { for {set i 0} {$i < 20000} {incr i} { dbh_$i close } }
} {1}
do_re_test 1.1.3 {
lindex $::log 0
+20
View File
@@ -15,13 +15,30 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix resetdb
do_not_use_codec
ifcapable !vtab||!compound {
finish_test
return
}
# In the "inmemory_journal" permutation, each new connection executes
# "PRAGMA journal_mode = memory". This fails with SQLITE_BUSY if attempted
# on a wal mode database with existing connections. For this and a few
# other reasons, this test is not run as part of "inmemory_journal".
#
# Permutation "journaltest" does not support wal mode.
#
if {[permutation]=="inmemory_journal"
|| [permutation]=="journaltest"
} {
finish_test
return
}
# Create a sample database
do_execsql_test 100 {
PRAGMA auto_vacuum = 0;
PRAGMA page_size=4096;
CREATE TABLE t1(a,b);
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<20)
@@ -82,6 +99,7 @@ db2 close
forcedelete test.db
sqlite3 db test.db
do_execsql_test 300 {
PRAGMA auto_vacuum = 0;
PRAGMA page_size=8192;
PRAGMA journal_mode=WAL;
CREATE TABLE t1(a,b);
@@ -118,6 +136,8 @@ do_test 330 {
} db2
} {1 {file is not a database}}
db2 cache flush ;# Required by permutation "prepare".
# Reset the database yet again. Verify that the page size and
# journal mode are preserved.
#
+1 -1
View File
@@ -256,7 +256,7 @@ do_test shell1-3.1.3 {
do_test shell1-3.1.4 {
# too many arguments
catchcmd "test.db" ".backup FOO BAR BAD"
} {1 {too many arguments to .backup}}
} {1 {Usage: .backup ?DB? ?--append? FILENAME}}
# .bail ON|OFF Stop after hitting an error. Default OFF
do_test shell1-3.2.1 {
+53 -6
View File
@@ -1247,10 +1247,11 @@ void testset_rtree(int p1, int p2){
unsigned mxCoord;
unsigned x0, x1, y0, y1, z0, z1;
unsigned iStep;
unsigned mxRowid;
int *aCheck = sqlite3_malloc( sizeof(int)*g.szTest*500 );
mxCoord = 15000;
n = g.szTest*500;
mxRowid = n = g.szTest*500;
speedtest1_begin_test(100, "%d INSERTs into an r-tree", n);
speedtest1_exec("BEGIN");
speedtest1_exec("CREATE VIRTUAL TABLE rt1 USING rtree(id,x0,x1,y0,y1,z0,z1)");
@@ -1277,7 +1278,7 @@ void testset_rtree(int p1, int p2){
speedtest1_exec("INSERT INTO t1 SELECT * FROM rt1");
speedtest1_end_test();
n = g.szTest*100;
n = g.szTest*200;
speedtest1_begin_test(110, "%d one-dimensional intersect slice queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE x0>=?1 AND x1<=?2");
iStep = mxCoord/n;
@@ -1290,7 +1291,7 @@ void testset_rtree(int p1, int p2){
speedtest1_end_test();
if( g.bVerify ){
n = g.szTest*100;
n = g.szTest*200;
speedtest1_begin_test(111, "Verify result from 1-D intersect slice queries");
speedtest1_prepare("SELECT count(*) FROM t1 WHERE x0>=?1 AND x1<=?2");
iStep = mxCoord/n;
@@ -1306,7 +1307,7 @@ void testset_rtree(int p1, int p2){
speedtest1_end_test();
}
n = g.szTest*100;
n = g.szTest*200;
speedtest1_begin_test(120, "%d one-dimensional overlap slice queries", n);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE y1>=?1 AND y0<=?2");
iStep = mxCoord/n;
@@ -1319,7 +1320,7 @@ void testset_rtree(int p1, int p2){
speedtest1_end_test();
if( g.bVerify ){
n = g.szTest*100;
n = g.szTest*200;
speedtest1_begin_test(121, "Verify result from 1-D overlap slice queries");
speedtest1_prepare("SELECT count(*) FROM t1 WHERE y1>=?1 AND y0<=?2");
iStep = mxCoord/n;
@@ -1336,7 +1337,7 @@ void testset_rtree(int p1, int p2){
}
n = g.szTest*100;
n = g.szTest*200;
speedtest1_begin_test(125, "%d custom geometry callback queries", n);
sqlite3_rtree_geometry_callback(g.db, "xslice", xsliceGeometryCallback, 0);
speedtest1_prepare("SELECT count(*) FROM rt1 WHERE id MATCH xslice(?1,?2)");
@@ -1373,6 +1374,52 @@ void testset_rtree(int p1, int p2){
speedtest1_run();
}
speedtest1_end_test();
n = g.szTest*50;
speedtest1_begin_test(150, "%d UPDATEs using rowid", n);
speedtest1_prepare("UPDATE rt1 SET x0=x0+100, x1=x1+100 WHERE id=?1");
for(i=1; i<=n; i++){
sqlite3_bind_int(g.pStmt, 1, (i*251)%mxRowid + 1);
speedtest1_run();
}
speedtest1_end_test();
n = g.szTest*5;
speedtest1_begin_test(155, "%d UPDATEs using one-dimensional overlap", n);
speedtest1_prepare("UPDATE rt1 SET x0=x0-100, x1=x1-100"
" WHERE y1>=?1 AND y0<=?1+5");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
speedtest1_run();
aCheck[i] = atoi(g.zResult);
}
speedtest1_end_test();
n = g.szTest*50;
speedtest1_begin_test(160, "%d DELETEs using rowid", n);
speedtest1_prepare("DELETE FROM rt1 WHERE id=?1");
for(i=1; i<=n; i++){
sqlite3_bind_int(g.pStmt, 1, (i*257)%mxRowid + 1);
speedtest1_run();
}
speedtest1_end_test();
n = g.szTest*5;
speedtest1_begin_test(165, "%d DELETEs using one-dimensional overlap", n);
speedtest1_prepare("DELETE FROM rt1 WHERE y1>=?1 AND y0<=?1+5");
iStep = mxCoord/n;
for(i=0; i<n; i++){
sqlite3_bind_int(g.pStmt, 1, i*iStep);
speedtest1_run();
aCheck[i] = atoi(g.zResult);
}
speedtest1_end_test();
speedtest1_begin_test(170, "Restore deleted entries using INSERT OR IGNORE");
speedtest1_exec("INSERT OR IGNORE INTO rt1 SELECT * FROM t1");
speedtest1_end_test();
}
#endif /* SQLITE_ENABLE_RTREE */
+11 -6
View File
@@ -51,15 +51,19 @@ ifcapable {update_delete_limit} {
catchsql {UPDATE t1 SET y=1 WHERE x=1 ORDER BY x}
} {1 {ORDER BY without LIMIT on UPDATE}}
execsql { DROP TABLE t1 }
# no AS on table sources
#
# UPDATE: As of version 3.24, AS clauses are allowed as part of
# UPDATE or DELETE statements.
do_test wherelimit-0.4 {
catchsql {DELETE FROM t1 AS a WHERE x=1}
} {1 {near "AS": syntax error}}
do_test wherelimit-0.5 {
catchsql {DELETE FROM t1 AS a WHERE a.x=1}
} {0 {}}
do_test wherelimit-0.5.1 {
catchsql {UPDATE t1 AS a SET y=1 WHERE x=1}
} {1 {near "AS": syntax error}}
} {0 {}}
do_test wherelimit-0.5.2 {
catchsql {UPDATE t1 AS a SET y=1 WHERE t1.x=1}
} {1 {no such column: t1.x}}
# OFFSET w/o LIMIT
do_test wherelimit-0.6 {
@@ -69,6 +73,7 @@ ifcapable {update_delete_limit} {
catchsql {UPDATE t1 SET y=1 WHERE x=1 OFFSET 2}
} {1 {near "OFFSET": syntax error}}
execsql { DROP TABLE t1 }
# check deletes w/o where clauses but with limit/offsets
create_test_data 5
+2 -1
View File
@@ -75,6 +75,7 @@ while {![eof $in]} {
if {[regexp {^case OP_} $line]} {
set line [split $line]
set name [string trim [lindex $line 1] :]
if {$name=="OP_Abortable"} continue; # put OP_Abortable last
set op($name) -1
set jump($name) 0
set in1($name) 0
@@ -113,7 +114,7 @@ while {![eof $in]} {
#
puts "/* Automatically generated. Do not edit */"
puts "/* See the tool/mkopcodeh.tcl script for details */"
foreach name {OP_Noop OP_Explain} {
foreach name {OP_Noop OP_Explain OP_Abortable} {
set jump($name) 0
set in1($name) 0
set in2($name) 0
+5 -1
View File
@@ -41,8 +41,12 @@ doExplain=0
doCachegrind=1
doVdbeProfile=0
doWal=1
doDiff=1
while test "$1" != ""; do
case $1 in
--nodiff)
doDiff=0
;;
--reprepare)
SPEEDTEST_OPTS="$SPEEDTEST_OPTS $1"
;;
@@ -179,6 +183,6 @@ if test $doVdbeProfile -eq 1; then
tclsh ../sqlite/tool/vdbe_profile.tcl >vdbeprofile-$NAME.txt
open vdbeprofile-$NAME.txt
fi
if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1; then
if test "$NAME" != "$BASELINE" -a $doVdbeProfile -ne 1 -a $doDiff -ne 0; then
fossil test-diff --tk -c 20 cout-$BASELINE.txt cout-$NAME.txt
fi