Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e088a6c0a | |||
| 51f1c6f3ec | |||
| 5051194270 | |||
| 8b2d8de3e2 | |||
| cdb6ce980b | |||
| 95063d8c90 | |||
| 451f89a896 | |||
| 065e4a8d29 | |||
| 23bef340be | |||
| 9f603fcefd | |||
| e238e31413 | |||
| ec9a25c7c7 | |||
| 7d9ad75a56 | |||
| 07f9e8f4f3 | |||
| ab2172e69f | |||
| 742efb6749 | |||
| 5415ab49b4 | |||
| 542bd6521e | |||
| fc7f31742d | |||
| 4d34766f4e | |||
| 6ef2dc137d | |||
| 9a1bb3f616 | |||
| 480620c713 | |||
| 3b9f154bb7 | |||
| 541ef2c36c | |||
| 45248de39a | |||
| 871f45441c | |||
| 7a43100afb | |||
| 1d9ea27f7e | |||
| 054a081555 | |||
| 7576a68c8c | |||
| c39b121a95 | |||
| f05dd03a6e | |||
| e6a85962e7 | |||
| 75b5f22c01 | |||
| eb110d9687 | |||
| 49d01abaac | |||
| e1cd73f671 | |||
| c004bd54e3 | |||
| e0ef4e2b47 | |||
| e065a18a4b | |||
| 8f78a528d5 | |||
| c5eeacd58b | |||
| 7797207554 | |||
| cf08f08d2c | |||
| 0518d06117 | |||
| eeb55d8694 | |||
| 8c5163a697 | |||
| cb49f5468e | |||
| 356cd76aa8 | |||
| 691b5c54b8 |
+12
-1
@@ -190,7 +190,8 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
table.lo threads.lo tokenize.lo treeview.lo trigger.lo \
|
||||
update.lo userauth.lo upsert.lo util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
vdbetrace.lo vdbevtab.lo \
|
||||
wal.lo walker.lo where.lo wherecode.lo whereexpr.lo \
|
||||
window.lo utf.lo vtab.lo
|
||||
|
||||
# Object files for the amalgamation.
|
||||
@@ -296,6 +297,7 @@ SRC = \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbesort.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/vdbevtab.c \
|
||||
$(TOP)/src/vdbeInt.h \
|
||||
$(TOP)/src/vtab.c \
|
||||
$(TOP)/src/vxworks.h \
|
||||
@@ -502,6 +504,7 @@ TESTSRC2 = \
|
||||
$(TOP)/src/vdbe.c \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/vdbevtab.c \
|
||||
$(TOP)/src/where.c \
|
||||
$(TOP)/src/wherecode.c \
|
||||
$(TOP)/src/whereexpr.c \
|
||||
@@ -607,6 +610,7 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
@@ -619,6 +623,7 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c
|
||||
DBFUZZ_OPT =
|
||||
|
||||
@@ -688,6 +693,7 @@ DBFUZZ2_OPTS = \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
@@ -1004,6 +1010,9 @@ vdbesort.lo: $(TOP)/src/vdbesort.c $(HDR)
|
||||
vdbetrace.lo: $(TOP)/src/vdbetrace.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbetrace.c
|
||||
|
||||
vdbevtab.lo: $(TOP)/src/vdbevtab.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vdbevtab.c
|
||||
|
||||
vtab.lo: $(TOP)/src/vtab.c $(HDR)
|
||||
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/vtab.c
|
||||
|
||||
@@ -1069,6 +1078,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/misc/uint.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
@@ -1210,6 +1220,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DESERIALIZE
|
||||
|
||||
TESTFIXTURE_SRC0 = $(TESTSRC2) libsqlite3.la
|
||||
|
||||
@@ -357,6 +357,7 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DBSTAT_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
!ENDIF
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1
|
||||
@@ -1353,6 +1354,7 @@ SRC01 = \
|
||||
$(TOP)\src\vdbemem.c \
|
||||
$(TOP)\src\vdbesort.c \
|
||||
$(TOP)\src\vdbetrace.c \
|
||||
$(TOP)\src\vdbevtab.c \
|
||||
$(TOP)\src\vtab.c \
|
||||
$(TOP)\src\wal.c \
|
||||
$(TOP)\src\walker.c \
|
||||
@@ -1684,6 +1686,7 @@ FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_OPTS = $(FUZZCHECK_OPTS) -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
|
||||
FUZZCHECK_SRC = $(TOP)\test\fuzzcheck.c $(TOP)\test\ossfuzz.c
|
||||
OSSSHELL_SRC = $(TOP)\test\ossshell.c $(TOP)\test\ossfuzz.c
|
||||
@@ -2109,6 +2112,9 @@ vdbesort.lo: $(TOP)\src\vdbesort.c $(HDR)
|
||||
vdbetrace.lo: $(TOP)\src\vdbetrace.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbetrace.c
|
||||
|
||||
vdbevtab.lo: $(TOP)\src\vdbevtab.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vdbevtab.c
|
||||
|
||||
vtab.lo: $(TOP)\src\vtab.c $(HDR)
|
||||
$(LTCOMPILE) $(CORE_COMPILE_OPTS) -c $(TOP)\src\vtab.c
|
||||
|
||||
@@ -2182,6 +2188,7 @@ SHELL_SRC = \
|
||||
$(TOP)\ext\misc\shathree.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\completion.c \
|
||||
$(TOP)\ext\misc\uint.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.c \
|
||||
$(TOP)\ext\expert\sqlite3expert.h \
|
||||
$(TOP)\ext\misc\memtrace.c \
|
||||
@@ -2352,6 +2359,7 @@ TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_STMTVTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DBPAGE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_BYTECODE_VTAB=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_JSON1=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) -DSQLITE_ENABLE_DESERIALIZE=1
|
||||
TESTFIXTURE_FLAGS = $(TESTFIXTURE_FLAGS) $(TEST_CCONV_OPTS)
|
||||
|
||||
+24
-10
@@ -962,6 +962,22 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
||||
return zRet;
|
||||
}
|
||||
|
||||
/*
|
||||
** Buffer z contains a positive integer value encoded as utf-8 text.
|
||||
** Decode this value and store it in *pnOut, returning the number of bytes
|
||||
** consumed. If an overflow error occurs return a negative value.
|
||||
*/
|
||||
int sqlite3Fts3ReadInt(const char *z, int *pnOut){
|
||||
u64 iVal = 0;
|
||||
int i;
|
||||
for(i=0; z[i]>='0' && z[i]<='9'; i++){
|
||||
iVal = iVal*10 + (z[i] - '0');
|
||||
if( iVal>0x7FFFFFFF ) return -1;
|
||||
}
|
||||
*pnOut = (int)iVal;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function interprets the string at (*pp) as a non-negative integer
|
||||
** value. It reads the integer and sets *pnOut to the value read, then
|
||||
@@ -977,19 +993,17 @@ static char *fts3WriteExprList(Fts3Table *p, const char *zFunc, int *pRc){
|
||||
*/
|
||||
static int fts3GobbleInt(const char **pp, int *pnOut){
|
||||
const int MAX_NPREFIX = 10000000;
|
||||
const char *p; /* Iterator pointer */
|
||||
int nInt = 0; /* Output value */
|
||||
|
||||
for(p=*pp; p[0]>='0' && p[0]<='9'; p++){
|
||||
nInt = nInt * 10 + (p[0] - '0');
|
||||
if( nInt>MAX_NPREFIX ){
|
||||
nInt = 0;
|
||||
break;
|
||||
}
|
||||
int nByte;
|
||||
nByte = sqlite3Fts3ReadInt(*pp, &nInt);
|
||||
if( nInt>MAX_NPREFIX ){
|
||||
nInt = 0;
|
||||
}
|
||||
if( nByte==0 ){
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
if( p==*pp ) return SQLITE_ERROR;
|
||||
*pnOut = nInt;
|
||||
*pp = p;
|
||||
*pp += nByte;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -591,6 +591,7 @@ int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
|
||||
int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
|
||||
void sqlite3Fts3CreateStatTable(int*, Fts3Table*);
|
||||
int sqlite3Fts3EvalTestDeferred(Fts3Cursor *pCsr, int *pRc);
|
||||
int sqlite3Fts3ReadInt(const char *z, int *pnOut);
|
||||
|
||||
/* fts3_tokenizer.c */
|
||||
const char *sqlite3Fts3NextToken(const char *, int *);
|
||||
|
||||
@@ -446,10 +446,7 @@ static int getNextNode(
|
||||
if( pKey->eType==FTSQUERY_NEAR ){
|
||||
assert( nKey==4 );
|
||||
if( zInput[4]=='/' && zInput[5]>='0' && zInput[5]<='9' ){
|
||||
nNear = 0;
|
||||
for(nKey=5; zInput[nKey]>='0' && zInput[nKey]<='9'; nKey++){
|
||||
nNear = nNear * 10 + (zInput[nKey] - '0');
|
||||
}
|
||||
nKey += 1+sqlite3Fts3ReadInt(&zInput[nKey+1], &nNear);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1415,6 +1415,7 @@ static int fts3SegReaderNext(
|
||||
*/
|
||||
if( pReader->nDoclist > pReader->nNode-(pReader->aDoclist-pReader->aNode)
|
||||
|| (pReader->nPopulate==0 && pReader->aDoclist[pReader->nDoclist-1])
|
||||
|| pReader->nDoclist==0
|
||||
){
|
||||
return FTS_CORRUPT_VTAB;
|
||||
}
|
||||
@@ -3068,11 +3069,11 @@ static void fts3ReadEndBlockField(
|
||||
if( zText ){
|
||||
int i;
|
||||
int iMul = 1;
|
||||
i64 iVal = 0;
|
||||
u64 iVal = 0;
|
||||
for(i=0; zText[i]>='0' && zText[i]<='9'; i++){
|
||||
iVal = iVal*10 + (zText[i] - '0');
|
||||
}
|
||||
*piEndBlock = iVal;
|
||||
*piEndBlock = (i64)iVal;
|
||||
while( zText[i]==' ' ) i++;
|
||||
iVal = 0;
|
||||
if( zText[i]=='-' ){
|
||||
@@ -3082,7 +3083,7 @@ static void fts3ReadEndBlockField(
|
||||
for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){
|
||||
iVal = iVal*10 + (zText[i] - '0');
|
||||
}
|
||||
*pnByte = (iVal * (i64)iMul);
|
||||
*pnByte = ((i64)iVal * (i64)iMul);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,778 @@
|
||||
/*
|
||||
** 2020-04-20
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
******************************************************************************
|
||||
**
|
||||
** This file implements a VFS shim that writes a checksum on each page
|
||||
** of an SQLite database file. When reading pages, the checksum is verified
|
||||
** and an error is raised if the checksum is incorrect.
|
||||
**
|
||||
** COMPILING
|
||||
**
|
||||
** This extension requires SQLite 3.32.0 or later. It uses the
|
||||
** sqlite3_database_file_object() interface which was added in
|
||||
** version 3.32.0, so it will not link with an earlier version of
|
||||
** SQLite.
|
||||
**
|
||||
** To build this extension as a separately loaded shared library or
|
||||
** DLL, use compiler command-lines similar to the following:
|
||||
**
|
||||
** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so
|
||||
** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib
|
||||
** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll
|
||||
**
|
||||
** You may want to add additional compiler options, of course,
|
||||
** according to the needs of your project.
|
||||
**
|
||||
** If you want to statically link this extension with your product,
|
||||
** then compile it like any other C-language module but add the
|
||||
** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that
|
||||
** it is being statically linked rather than dynamically linked
|
||||
**
|
||||
** LOADING
|
||||
**
|
||||
** To load this extension as a shared library, you first have to
|
||||
** bring up a dummy SQLite database connection to use as the argument
|
||||
** to the sqlite3_load_extension() API call. Then you invoke the
|
||||
** sqlite3_load_extension() API and shutdown the dummy database
|
||||
** connection. All subsequent database connections that are opened
|
||||
** will include this extension. For example:
|
||||
**
|
||||
** sqlite3 *db;
|
||||
** sqlite3_open(":memory:", &db);
|
||||
** sqlite3_load_extention(db, "./cksumvfs");
|
||||
** sqlite3_close(db);
|
||||
**
|
||||
** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and
|
||||
** statically linked against the application, initialize it using
|
||||
** a single API call as follows:
|
||||
**
|
||||
** sqlite3_cksumvfs_init();
|
||||
**
|
||||
** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new
|
||||
** default VFS and it uses the prior default VFS as the next VFS
|
||||
** down in the stack. This is normally what you want. However, it
|
||||
** complex situations where multiple VFS shims are being loaded,
|
||||
** it might be important to ensure that cksumvfs is loaded in the
|
||||
** correct order so that it sequences itself into the default VFS
|
||||
** Shim stack in the right order.
|
||||
**
|
||||
** USING
|
||||
**
|
||||
** Open database connections using the sqlite3_open() or
|
||||
** sqlite3_open_v2() interfaces, as normal. Ordinary database files
|
||||
** (without a checksum) will operate normally. Databases with
|
||||
** checksums will return an SQLITE_IOERR_DATA error if a page is
|
||||
** encountered that contains an invalid checksum.
|
||||
**
|
||||
** Checksumming only works on databases that have a reserve-bytes
|
||||
** value of exactly 8. The default value for reserve-bytes is 0.
|
||||
** Hence, newly created database files will omit the checksum by
|
||||
** default. To create a database that includes a checksum, change
|
||||
** the reserve-bytes value to 8 by runing:
|
||||
**
|
||||
** int n = 8;
|
||||
** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVED_BYTES, &n);
|
||||
**
|
||||
** If you do this immediately after creating a new database file,
|
||||
** before anything else has been written into the file, then that
|
||||
** might be all that you need to do. Otherwise, the API call
|
||||
** above should be followed by:
|
||||
**
|
||||
** sqlite3_exec(db, "VACUUM", 0, 0, 0);
|
||||
**
|
||||
** It never hurts to run the VACUUM, even if you don't need it.
|
||||
** If the database is in WAL mode, you should shutdown and
|
||||
** reopen all database connections before continuing.
|
||||
**
|
||||
** From the CLI, use the ".filectrl reserve_bytes 8" command,
|
||||
** followed by "VACUUM;".
|
||||
**
|
||||
** Note that SQLite allows the number of reserve-bytes to be
|
||||
** increased but not decreased. So if a database file already
|
||||
** has a reserve-bytes value greater than 8, there is no way to
|
||||
** activate checksumming on that database, other than to dump
|
||||
** and restore the database file. Note also that other extensions
|
||||
** might also make use of the reserve-bytes. Checksumming will
|
||||
** be incompatible with those other extensions.
|
||||
**
|
||||
** VERIFICATION OF CHECKSUMS
|
||||
**
|
||||
** If any checksum is incorrect, the "PRAGMA quick_check" command
|
||||
** will find it. To verify that checksums are actually enabled
|
||||
** and running, use the following query:
|
||||
**
|
||||
** SELECT count(*), verify_checksum(data)
|
||||
** FROM sqlite_dbpage
|
||||
** GROUP BY 2;
|
||||
**
|
||||
** There are three possible outputs form the verify_checksum()
|
||||
** function: 1, 0, and NULL. 1 is returned if the checksum is
|
||||
** correct. 0 is returned if the checksum is incorrect. NULL
|
||||
** is returned if the page is unreadable. If checksumming is
|
||||
** enabled, the read will fail if the checksum is wrong, so the
|
||||
** usual result from verify_checksum() on a bad checksum is NULL.
|
||||
**
|
||||
** If everything is OK, the query above should return a single
|
||||
** row where the second column is 1. Any other result indicates
|
||||
** either that there is a checksum error, or checksum validation
|
||||
** is disabled.
|
||||
**
|
||||
** CONTROLLING CHECKSUM VERIFICATION
|
||||
**
|
||||
** The cksumvfs extension implements a new PRAGMA statement that can
|
||||
** be used to disable, re-enable, or query the status of checksum
|
||||
** verification:
|
||||
**
|
||||
** PRAGMA checksum_verification; -- query status
|
||||
** PRAGMA checksum_verification=OFF; -- disable verification
|
||||
** PRAGMA checksum_verification=ON; -- re-enable verification
|
||||
**
|
||||
** The "checksum_verification" pragma will return "1" (true) or "0"
|
||||
** (false) if checksum verification is enabled or disabled, respectively.
|
||||
** "Verification" in this context means the feature that causes
|
||||
** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while
|
||||
** reading. Checksums are always kept up-to-date as long as the
|
||||
** reserve-bytes value of the database is 8, regardless of the setting
|
||||
** of this pragma. Checksum verification can be disabled (for example)
|
||||
** to do forensic analysis of a database that has previously reported
|
||||
** a checksum error.
|
||||
**
|
||||
** The "checksum_verification" pragma will always respond with "0" if
|
||||
** the database file does not have a reserve-bytes value of 8. The
|
||||
** pragma will return no rows at all if the cksumvfs extension is
|
||||
** not loaded.
|
||||
**
|
||||
** IMPLEMENTATION NOTES
|
||||
**
|
||||
** The checksum is stored in the last 8 bytes of each page. This
|
||||
** module only operates if the "bytes of reserved space on each page"
|
||||
** value at offset 20 the SQLite database header is exactly 8. If
|
||||
** the reserved-space value is not 8, this module is a no-op.
|
||||
*/
|
||||
#ifdef SQLITE_CKSUMVFS_STATIC
|
||||
# include "sqlite3.h"
|
||||
#else
|
||||
# include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/*
|
||||
** Forward declaration of objects used by this utility
|
||||
*/
|
||||
typedef struct sqlite3_vfs CksmVfs;
|
||||
typedef struct CksmFile CksmFile;
|
||||
|
||||
/*
|
||||
** Useful datatype abbreviations
|
||||
*/
|
||||
#if !defined(SQLITE_CORE)
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned int u32;
|
||||
#endif
|
||||
|
||||
/* Access to a lower-level VFS that (might) implement dynamic loading,
|
||||
** access to randomness, etc.
|
||||
*/
|
||||
#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
|
||||
#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))
|
||||
|
||||
/* An open file */
|
||||
struct CksmFile {
|
||||
sqlite3_file base; /* IO methods */
|
||||
const char *zFName; /* Original name of the file */
|
||||
char computeCksm; /* True to compute checksums.
|
||||
** Always true if reserve size is 8. */
|
||||
char verifyCksm; /* True to verify checksums */
|
||||
char isWal; /* True if processing a WAL file */
|
||||
CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */
|
||||
};
|
||||
|
||||
/*
|
||||
** Methods for CksmFile
|
||||
*/
|
||||
static int cksmClose(sqlite3_file*);
|
||||
static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
|
||||
static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
|
||||
static int cksmTruncate(sqlite3_file*, sqlite3_int64 size);
|
||||
static int cksmSync(sqlite3_file*, int flags);
|
||||
static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize);
|
||||
static int cksmLock(sqlite3_file*, int);
|
||||
static int cksmUnlock(sqlite3_file*, int);
|
||||
static int cksmCheckReservedLock(sqlite3_file*, int *pResOut);
|
||||
static int cksmFileControl(sqlite3_file*, int op, void *pArg);
|
||||
static int cksmSectorSize(sqlite3_file*);
|
||||
static int cksmDeviceCharacteristics(sqlite3_file*);
|
||||
static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
|
||||
static int cksmShmLock(sqlite3_file*, int offset, int n, int flags);
|
||||
static void cksmShmBarrier(sqlite3_file*);
|
||||
static int cksmShmUnmap(sqlite3_file*, int deleteFlag);
|
||||
static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
|
||||
static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
|
||||
|
||||
/*
|
||||
** Methods for CksmVfs
|
||||
*/
|
||||
static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
|
||||
static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir);
|
||||
static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *);
|
||||
static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
|
||||
static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename);
|
||||
static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
|
||||
static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
|
||||
static void cksmDlClose(sqlite3_vfs*, void*);
|
||||
static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut);
|
||||
static int cksmSleep(sqlite3_vfs*, int microseconds);
|
||||
static int cksmCurrentTime(sqlite3_vfs*, double*);
|
||||
static int cksmGetLastError(sqlite3_vfs*, int, char *);
|
||||
static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
|
||||
static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
|
||||
static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z);
|
||||
static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName);
|
||||
|
||||
static sqlite3_vfs cksm_vfs = {
|
||||
3, /* iVersion (set when registered) */
|
||||
0, /* szOsFile (set when registered) */
|
||||
1024, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"cksmvfs", /* zName */
|
||||
0, /* pAppData (set when registered) */
|
||||
cksmOpen, /* xOpen */
|
||||
cksmDelete, /* xDelete */
|
||||
cksmAccess, /* xAccess */
|
||||
cksmFullPathname, /* xFullPathname */
|
||||
cksmDlOpen, /* xDlOpen */
|
||||
cksmDlError, /* xDlError */
|
||||
cksmDlSym, /* xDlSym */
|
||||
cksmDlClose, /* xDlClose */
|
||||
cksmRandomness, /* xRandomness */
|
||||
cksmSleep, /* xSleep */
|
||||
cksmCurrentTime, /* xCurrentTime */
|
||||
cksmGetLastError, /* xGetLastError */
|
||||
cksmCurrentTimeInt64, /* xCurrentTimeInt64 */
|
||||
cksmSetSystemCall, /* xSetSystemCall */
|
||||
cksmGetSystemCall, /* xGetSystemCall */
|
||||
cksmNextSystemCall /* xNextSystemCall */
|
||||
};
|
||||
|
||||
static const sqlite3_io_methods cksm_io_methods = {
|
||||
3, /* iVersion */
|
||||
cksmClose, /* xClose */
|
||||
cksmRead, /* xRead */
|
||||
cksmWrite, /* xWrite */
|
||||
cksmTruncate, /* xTruncate */
|
||||
cksmSync, /* xSync */
|
||||
cksmFileSize, /* xFileSize */
|
||||
cksmLock, /* xLock */
|
||||
cksmUnlock, /* xUnlock */
|
||||
cksmCheckReservedLock, /* xCheckReservedLock */
|
||||
cksmFileControl, /* xFileControl */
|
||||
cksmSectorSize, /* xSectorSize */
|
||||
cksmDeviceCharacteristics, /* xDeviceCharacteristics */
|
||||
cksmShmMap, /* xShmMap */
|
||||
cksmShmLock, /* xShmLock */
|
||||
cksmShmBarrier, /* xShmBarrier */
|
||||
cksmShmUnmap, /* xShmUnmap */
|
||||
cksmFetch, /* xFetch */
|
||||
cksmUnfetch /* xUnfetch */
|
||||
};
|
||||
|
||||
/* Do byte swapping on a unsigned 32-bit integer */
|
||||
#define BYTESWAP32(x) ( \
|
||||
(((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
|
||||
+ (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
|
||||
)
|
||||
|
||||
/* Compute a checksum on a buffer */
|
||||
static void cksmCompute(
|
||||
u8 *a, /* Content to be checksummed */
|
||||
int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
|
||||
u8 *aOut /* OUT: Final 8-byte checksum value output */
|
||||
){
|
||||
u32 s1 = 0, s2 = 0;
|
||||
u32 *aData = (u32*)a;
|
||||
u32 *aEnd = (u32*)&a[nByte];
|
||||
u32 x = 1;
|
||||
|
||||
assert( nByte>=8 );
|
||||
assert( (nByte&0x00000007)==0 );
|
||||
assert( nByte<=65536 );
|
||||
|
||||
if( 1 == *(u8*)&x ){
|
||||
/* Little-endian */
|
||||
do {
|
||||
s1 += *aData++ + s2;
|
||||
s2 += *aData++ + s1;
|
||||
}while( aData<aEnd );
|
||||
}else{
|
||||
/* Big-endian */
|
||||
do {
|
||||
s1 += BYTESWAP32(aData[0]) + s2;
|
||||
s2 += BYTESWAP32(aData[1]) + s1;
|
||||
aData += 2;
|
||||
}while( aData<aEnd );
|
||||
s1 = BYTESWAP32(s1);
|
||||
s2 = BYTESWAP32(s2);
|
||||
}
|
||||
memcpy(aOut, &s1, 4);
|
||||
memcpy(aOut+4, &s2, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: verify_checksum(BLOB)
|
||||
**
|
||||
** Return 0 or 1 if the checksum is invalid or valid. Or return
|
||||
** NULL if the input is not a BLOB that is the right size for a
|
||||
** database page.
|
||||
*/
|
||||
static void cksmVerifyFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int nByte;
|
||||
u8 *data;
|
||||
u8 cksum[8];
|
||||
data = (u8*)sqlite3_value_blob(argv[0]);
|
||||
if( data==0 ) return;
|
||||
if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return;
|
||||
nByte = sqlite3_value_bytes(argv[0]);
|
||||
if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return;
|
||||
cksmCompute(data, nByte-8, cksum);
|
||||
sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a cksm-file.
|
||||
*/
|
||||
static int cksmClose(sqlite3_file *pFile){
|
||||
CksmFile *p = (CksmFile *)pFile;
|
||||
if( p->pPartner ){
|
||||
assert( p->pPartner->pPartner==p );
|
||||
p->pPartner->pPartner = 0;
|
||||
p->pPartner = 0;
|
||||
}
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xClose(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a cksm-file.
|
||||
*/
|
||||
static int cksmRead(
|
||||
sqlite3_file *pFile,
|
||||
void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
int rc;
|
||||
CksmFile *p = (CksmFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
}
|
||||
}
|
||||
/* Verify the checksum if (1) the size seems appropriate for a database
|
||||
** page, and if (2) checksum verification is enabled. But (3) do not
|
||||
** verify the checksums on a WAL page if the main database file
|
||||
** has subsequently turned off checksums.
|
||||
*/
|
||||
if( iAmt>=512 /* (1) */
|
||||
&& p->verifyCksm /* (2) */
|
||||
&& (!p->isWal || (p->pPartner!=0 && p->pPartner->verifyCksm)) /* (3) */
|
||||
){
|
||||
u8 cksum[8];
|
||||
cksmCompute((u8*)zBuf, iAmt-8, cksum);
|
||||
if( memcmp(zBuf+iAmt-8, cksum, 8)!=0 ){
|
||||
sqlite3_log(SQLITE_IOERR_DATA,
|
||||
"checksum fault offset %lld of \"%s\"",
|
||||
iOfst, p->zFName);
|
||||
rc = SQLITE_IOERR_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write data to a cksm-file.
|
||||
*/
|
||||
static int cksmWrite(
|
||||
sqlite3_file *pFile,
|
||||
const void *zBuf,
|
||||
int iAmt,
|
||||
sqlite_int64 iOfst
|
||||
){
|
||||
CksmFile *p = (CksmFile *)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
if( iOfst==0 && iAmt>=100 && memcmp(zBuf,"SQLite format 3",16)==0 ){
|
||||
u8 *d = (u8*)zBuf;
|
||||
char hasCorrectReserveSize = (d[20]==8);
|
||||
if( hasCorrectReserveSize!=p->computeCksm ){
|
||||
p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
|
||||
}
|
||||
}
|
||||
/* If the write size is appropriate for a database page and if
|
||||
** checksums where ever enabled, then it will be safe to compute
|
||||
** the checksums. The reserve byte size might have increased, but
|
||||
** it will never decrease. And because it cannot decrease, the
|
||||
** checksum will not overwrite anything.
|
||||
*/
|
||||
if( iAmt>=512 && p->computeCksm ){
|
||||
cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
|
||||
}
|
||||
return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
|
||||
}
|
||||
|
||||
/*
|
||||
** Truncate a cksm-file.
|
||||
*/
|
||||
static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xTruncate(pFile, size);
|
||||
}
|
||||
|
||||
/*
|
||||
** Sync a cksm-file.
|
||||
*/
|
||||
static int cksmSync(sqlite3_file *pFile, int flags){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xSync(pFile, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the current file-size of a cksm-file.
|
||||
*/
|
||||
static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
|
||||
CksmFile *p = (CksmFile *)pFile;
|
||||
pFile = ORIGFILE(p);
|
||||
return pFile->pMethods->xFileSize(pFile, pSize);
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock a cksm-file.
|
||||
*/
|
||||
static int cksmLock(sqlite3_file *pFile, int eLock){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xLock(pFile, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Unlock a cksm-file.
|
||||
*/
|
||||
static int cksmUnlock(sqlite3_file *pFile, int eLock){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xUnlock(pFile, eLock);
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if another file-handle holds a RESERVED lock on a cksm-file.
|
||||
*/
|
||||
static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
|
||||
}
|
||||
|
||||
/*
|
||||
** File control method. For custom operations on a cksm-file.
|
||||
*/
|
||||
static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
|
||||
int rc;
|
||||
CksmFile *p = (CksmFile*)pFile;
|
||||
pFile = ORIGFILE(pFile);
|
||||
if( op==SQLITE_FCNTL_PRAGMA ){
|
||||
char **azArg = (char**)pArg;
|
||||
assert( azArg[1]!=0 );
|
||||
if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){
|
||||
char *zArg = azArg[2];
|
||||
if( zArg!=0 ){
|
||||
if( (zArg[0]>='1' && zArg[0]<='9')
|
||||
|| sqlite3_strlike("enable%",zArg,0)==0
|
||||
|| sqlite3_stricmp("yes",zArg)==0
|
||||
|| sqlite3_stricmp("on",zArg)==0
|
||||
){
|
||||
p->verifyCksm = p->computeCksm;
|
||||
}else{
|
||||
p->verifyCksm = 0;
|
||||
}
|
||||
}
|
||||
azArg[0] = sqlite3_mprintf("%d",p->verifyCksm);
|
||||
return SQLITE_OK;
|
||||
}else if( p->computeCksm && azArg[2]!=0
|
||||
&& sqlite3_stricmp(azArg[1], "page_size")==0 ){
|
||||
/* Do not allow page size changes on a checksum database */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
rc = pFile->pMethods->xFileControl(pFile, op, pArg);
|
||||
if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
|
||||
*(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sector-size in bytes for a cksm-file.
|
||||
*/
|
||||
static int cksmSectorSize(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xSectorSize(pFile);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the device characteristic flags supported by a cksm-file.
|
||||
*/
|
||||
static int cksmDeviceCharacteristics(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xDeviceCharacteristics(pFile);
|
||||
}
|
||||
|
||||
/* Create a shared memory file mapping */
|
||||
static int cksmShmMap(
|
||||
sqlite3_file *pFile,
|
||||
int iPg,
|
||||
int pgsz,
|
||||
int bExtend,
|
||||
void volatile **pp
|
||||
){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
|
||||
}
|
||||
|
||||
/* Perform locking on a shared-memory segment */
|
||||
static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmLock(pFile,offset,n,flags);
|
||||
}
|
||||
|
||||
/* Memory barrier operation on shared memory */
|
||||
static void cksmShmBarrier(sqlite3_file *pFile){
|
||||
pFile = ORIGFILE(pFile);
|
||||
pFile->pMethods->xShmBarrier(pFile);
|
||||
}
|
||||
|
||||
/* Unmap a shared memory segment */
|
||||
static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
|
||||
}
|
||||
|
||||
/* Fetch a page of a memory-mapped file */
|
||||
static int cksmFetch(
|
||||
sqlite3_file *pFile,
|
||||
sqlite3_int64 iOfst,
|
||||
int iAmt,
|
||||
void **pp
|
||||
){
|
||||
CksmFile *p = (CksmFile *)pFile;
|
||||
if( p->computeCksm ){
|
||||
*pp = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
|
||||
}
|
||||
|
||||
/* Release a memory-mapped page */
|
||||
static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
|
||||
pFile = ORIGFILE(pFile);
|
||||
return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a cksm file handle.
|
||||
*/
|
||||
static int cksmOpen(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_file *pFile,
|
||||
int flags,
|
||||
int *pOutFlags
|
||||
){
|
||||
CksmFile *p;
|
||||
sqlite3_file *pSubFile;
|
||||
sqlite3_vfs *pSubVfs;
|
||||
int rc;
|
||||
pSubVfs = ORIGVFS(pVfs);
|
||||
if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
|
||||
return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
|
||||
}
|
||||
p = (CksmFile*)pFile;
|
||||
memset(p, 0, sizeof(*p));
|
||||
pSubFile = ORIGFILE(pFile);
|
||||
p->base.pMethods = &cksm_io_methods;
|
||||
rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
|
||||
if( rc ) goto cksm_open_done;
|
||||
if( flags & SQLITE_OPEN_WAL ){
|
||||
sqlite3_file *pDb = sqlite3_database_file_object(zName);
|
||||
p->pPartner = (CksmFile*)pDb;
|
||||
assert( p->pPartner->pPartner==0 );
|
||||
p->pPartner->pPartner = p;
|
||||
p->isWal = 1;
|
||||
p->computeCksm = p->pPartner->computeCksm;
|
||||
}else{
|
||||
p->isWal = 0;
|
||||
p->computeCksm = 0;
|
||||
}
|
||||
p->zFName = zName;
|
||||
cksm_open_done:
|
||||
if( rc ) pFile->pMethods = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** All other VFS methods are pass-thrus.
|
||||
*/
|
||||
static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
|
||||
return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
|
||||
}
|
||||
static int cksmAccess(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int flags,
|
||||
int *pResOut
|
||||
){
|
||||
return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
|
||||
}
|
||||
static int cksmFullPathname(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zPath,
|
||||
int nOut,
|
||||
char *zOut
|
||||
){
|
||||
return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
|
||||
}
|
||||
static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){
|
||||
return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
|
||||
}
|
||||
static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
|
||||
ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
|
||||
}
|
||||
static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
|
||||
return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
|
||||
}
|
||||
static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){
|
||||
ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
|
||||
}
|
||||
static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
|
||||
return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
|
||||
}
|
||||
static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){
|
||||
return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
|
||||
}
|
||||
static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
|
||||
return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
|
||||
}
|
||||
static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
|
||||
return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
|
||||
}
|
||||
static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
|
||||
return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
|
||||
}
|
||||
static int cksmSetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName,
|
||||
sqlite3_syscall_ptr pCall
|
||||
){
|
||||
return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
|
||||
}
|
||||
static sqlite3_syscall_ptr cksmGetSystemCall(
|
||||
sqlite3_vfs *pVfs,
|
||||
const char *zName
|
||||
){
|
||||
return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
|
||||
}
|
||||
static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
|
||||
return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
|
||||
}
|
||||
|
||||
/* Register the verify_checksum() SQL function.
|
||||
*/
|
||||
static int cksmRegisterFunc(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc;
|
||||
if( db==0 ) return SQLITE_OK;
|
||||
rc = sqlite3_create_function(db, "verify_checksum", 1,
|
||||
SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
|
||||
0, cksmVerifyFunc, 0, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Register the cksum VFS as the default VFS for the system.
|
||||
** Also make arrangements to automatically register the "verify_checksum()"
|
||||
** SQL function on each new database connection.
|
||||
*/
|
||||
static int cksmRegisterVfs(void){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_vfs *pOrig;
|
||||
if( sqlite3_vfs_find("cksum")!=0 ) return SQLITE_OK;
|
||||
pOrig = sqlite3_vfs_find(0);
|
||||
cksm_vfs.iVersion = pOrig->iVersion;
|
||||
cksm_vfs.pAppData = pOrig;
|
||||
cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile);
|
||||
rc = sqlite3_vfs_register(&cksm_vfs, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_CKSUMVFS_STATIC)
|
||||
/* This variant of the initializer runs when the extension is
|
||||
** statically linked.
|
||||
*/
|
||||
int sqlite3_register_cksumvfs(const char *NotUsed){
|
||||
(void)NotUsed;
|
||||
return cksmRegisterVfs();
|
||||
}
|
||||
#endif /* defined(SQLITE_CKSUMVFS_STATIC */
|
||||
|
||||
#if !defined(SQLITE_CKSUMVFS_STATIC)
|
||||
/* This variant of the initializer function is used when the
|
||||
** extension is shared library to be loaded at run-time.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
/*
|
||||
** This routine is called by sqlite3_load_extension() when the
|
||||
** extension is first loaded.
|
||||
***/
|
||||
int sqlite3_cksumvfs_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
int rc;
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* not used */
|
||||
rc = cksmRegisterFunc(db, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = cksmRegisterVfs();
|
||||
}
|
||||
if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
|
||||
return rc;
|
||||
}
|
||||
#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
** 2020-04-14
|
||||
**
|
||||
** 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 SQLite extension implements the UINT collating sequence.
|
||||
**
|
||||
** UINT works like BINARY for text, except that embedded strings
|
||||
** of digits compare in numeric order.
|
||||
**
|
||||
** * Leading zeros are handled properly, in the sense that
|
||||
** they do not mess of the maginitude comparison of embedded
|
||||
** strings of digits. "x00123y" is equal to "x123y".
|
||||
**
|
||||
** * Only unsigned integers are recognized. Plus and minus
|
||||
** signs are ignored. Decimal points and exponential notation
|
||||
** are ignored.
|
||||
**
|
||||
** * Embedded integers can be of arbitrary length. Comparison
|
||||
** is *not* limited integers that can be expressed as a
|
||||
** 64-bit machine integer.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** Compare text in lexicographic order, except strings of digits
|
||||
** compare in numeric order.
|
||||
*/
|
||||
static int uintCollFunc(
|
||||
void *notUsed,
|
||||
int nKey1, const void *pKey1,
|
||||
int nKey2, const void *pKey2
|
||||
){
|
||||
const unsigned char *zA = (const unsigned char*)pKey1;
|
||||
const unsigned char *zB = (const unsigned char*)pKey2;
|
||||
int i=0, j=0, x;
|
||||
while( i<nKey1 && j<nKey2 ){
|
||||
x = zA[i] - zB[j];
|
||||
if( isdigit(zA[i]) ){
|
||||
int k;
|
||||
if( !isdigit(zB[j]) ) return x;
|
||||
while( i<nKey1 && zA[i]=='0' ){ i++; }
|
||||
while( j<nKey2 && zB[j]=='0' ){ j++; }
|
||||
k = 0;
|
||||
while( i+k<nKey1 && isdigit(zA[i+k])
|
||||
&& j+k<nKey2 && isdigit(zB[j+k]) ){
|
||||
k++;
|
||||
}
|
||||
if( i+k<nKey1 && isdigit(zA[i+k]) ){
|
||||
return +1;
|
||||
}else if( j+k<nKey2 && isdigit(zB[j+k]) ){
|
||||
return -1;
|
||||
}else{
|
||||
x = memcmp(zA+i, zB+j, k);
|
||||
if( x ) return x;
|
||||
i += k;
|
||||
j += k;
|
||||
}
|
||||
}else if( x ){
|
||||
return x;
|
||||
}else{
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return (nKey1 - i) - (nKey2 - j);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_uint_init(
|
||||
sqlite3 *db,
|
||||
char **pzErrMsg,
|
||||
const sqlite3_api_routines *pApi
|
||||
){
|
||||
SQLITE_EXTENSION_INIT2(pApi);
|
||||
(void)pzErrMsg; /* Unused parameter */
|
||||
return sqlite3_create_collation(db, "uint", SQLITE_UTF8, 0, uintCollFunc);
|
||||
}
|
||||
@@ -74,7 +74,8 @@ LIBOBJ+= vdbe.o parse.o \
|
||||
table.o threads.o tokenize.o treeview.o trigger.o \
|
||||
update.o upsert.o userauth.o util.o vacuum.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \
|
||||
vdbetrace.o vdbevtab.o \
|
||||
wal.o walker.o where.o wherecode.o whereexpr.o \
|
||||
utf.o vtab.o window.o
|
||||
|
||||
LIBOBJ += sqlite3session.o
|
||||
@@ -173,6 +174,7 @@ SRC = \
|
||||
$(TOP)/src/vdbemem.c \
|
||||
$(TOP)/src/vdbesort.c \
|
||||
$(TOP)/src/vdbetrace.c \
|
||||
$(TOP)/src/vdbevtab.c \
|
||||
$(TOP)/src/vdbeInt.h \
|
||||
$(TOP)/src/vtab.c \
|
||||
$(TOP)/src/vxworks.h \
|
||||
@@ -526,6 +528,7 @@ SHELL_OPT += -DSQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
|
||||
SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC
|
||||
FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1
|
||||
FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5
|
||||
@@ -536,6 +539,7 @@ FUZZCHECK_OPT += -DSQLITE_ENABLE_FTS4
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_RTREE
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_GEOPOLY
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB
|
||||
FUZZCHECK_OPT += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
DBFUZZ_OPT =
|
||||
KV_OPT = -DSQLITE_THREADSAFE=0 -DSQLITE_DIRECT_OVERFLOW_READ
|
||||
ST_OPT = -DSQLITE_THREADSAFE=0
|
||||
@@ -586,6 +590,7 @@ DBFUZZ2_OPTS = \
|
||||
-DSQLITE_ENABLE_DESERIALIZE \
|
||||
-DSQLITE_DEBUG \
|
||||
-DSQLITE_ENABLE_DBSTAT_VTAB \
|
||||
-DSQLITE_ENABLE_BYTECODE_VTAB \
|
||||
-DSQLITE_ENABLE_RTREE \
|
||||
-DSQLITE_ENABLE_FTS4 \
|
||||
-DSQLITE_ENABLE_FTS5
|
||||
@@ -733,6 +738,7 @@ SHELL_SRC = \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/completion.c \
|
||||
$(TOP)/ext/misc/sqlar.c \
|
||||
$(TOP)/ext/misc/uint.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.c \
|
||||
$(TOP)/ext/expert/sqlite3expert.h \
|
||||
$(TOP)/ext/misc/zipfile.c \
|
||||
@@ -894,6 +900,7 @@ TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_STMTVTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_DBPAGE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DSQLITE_ENABLE_BYTECODE_VTAB
|
||||
TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit
|
||||
|
||||
testfixture$(EXE): $(TESTSRC2) libsqlite3.a $(TESTSRC) $(TOP)/src/tclsqlite.c
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
C When\scompiling\sthe\sshell\sfor\sWinRT,\savoid\susing\sWin32\sAPIs\sthat\sare\sunavailable.
|
||||
D 2020-04-09T15:31:22.553
|
||||
C Corner-case\schanges\sto\sthe\sbytecode\svirtual\stable\sfor\stestability\sand\ncorrectness.
|
||||
D 2020-05-02T00:01:39.619
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 9dfc7936f675785309b74d09202bb656732325e65df889e5aaa18cc8932e5b0c
|
||||
F Makefile.in 280cf54350738dfd567bd97ae1bff1bf68c64658c4d5ff21be9cae117e92f063
|
||||
F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241
|
||||
F Makefile.msc fab23c6b10cb6f06a7e9c407fc2e35cb184a6d653f1b793bda87fcee2eafa4f6
|
||||
F Makefile.msc d9232f9339da7d2b82611cb148734d36be4cc90e17a968882e71d9bf75e512df
|
||||
F README.md 1514a365ffca3c138e00c5cc839906108a01011a6b082bad19b09781e3aa498a
|
||||
F VERSION 980d78a2ce04a1fd0ebefbaabd665f7f9186563820629ee29c6e350e96f19b52
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -82,11 +82,11 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c 2a9dd452003a143248e68449302da80dd0c43df72195b56577e3562e43c408a0
|
||||
F ext/fts3/fts3.c de2cc136ccc6128e948ffd5d74636756014b2430d6237d7002c3bc3ceb1ae3ae
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h f091030b976045e7df91af2337935952b477cdbd9f48058c44c965684484cb50
|
||||
F ext/fts3/fts3Int.h 2c59cc46aefde134c1782e89a6a5384710ddcd4e783071337aa5d43d07269be3
|
||||
F ext/fts3/fts3_aux.c 96708c8b3a7d9b8ca1b68ea2b7e503e283f20e95f145becadedfad096dbd0f34
|
||||
F ext/fts3/fts3_expr.c b132af223e90e35b9f9efa9fe63d6ae737d34153a3b6066736086df8abc78a1f
|
||||
F ext/fts3/fts3_expr.c f081e38da641724cd72c20e23b71db2bf4d0c9517c14637442f6910259f11a34
|
||||
F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116
|
||||
@@ -100,7 +100,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3
|
||||
F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004
|
||||
F ext/fts3/fts3_unicode.c 4b9af6151c29b35ed09574937083cece7c31e911f69615e168a39677569b684d
|
||||
F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f
|
||||
F ext/fts3/fts3_write.c eb5c0184762a310003762db4ebd5ddcce097d9bb08804279ba33a42907f847a6
|
||||
F ext/fts3/fts3_write.c ed869b24d074f2498bdbef915d6db1f88c604ca5811502112061932a0bed5133
|
||||
F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
|
||||
F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
|
||||
F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73
|
||||
@@ -285,6 +285,7 @@ F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb
|
||||
F ext/misc/blobio.c a867c4c4617f6ec223a307ebfe0eabb45e0992f74dd47722b96f3e631c0edb2a
|
||||
F ext/misc/btreeinfo.c 26004b7a6be320ec08fc20ca8d0f01fccb00a98cbe0f3197446794ff2a506aa3
|
||||
F ext/misc/carray.c 91e9a7f512fda934894bed30464552fffa7d3073b5be04189ae0bd0c59f26bfd
|
||||
F ext/misc/cksumvfs.c 755627c9112a000bc89653cb5038e080e69c58fa0a5c8e9ebd747f24e5fc01c9
|
||||
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
|
||||
F ext/misc/completion.c a0efe03edfdc4f717c61e6c9b0bfe2708ff7878010dae3174980a68fdf76aabc
|
||||
F ext/misc/compress.c 3354c77a7c8e86e07d849916000cdac451ed96500bfb5bd83b20eb61eee012c9
|
||||
@@ -320,6 +321,7 @@ F ext/misc/sqlar.c c9e5d58544e1506135806a1e0f525f92d4bb6bb125348dce469d778fb334f
|
||||
F ext/misc/stmt.c 8a8dc4675042e4551e4afe99b8d0cc7a4a2fc1a8dacc0a9ce1b1bbff145da93d
|
||||
F ext/misc/templatevtab.c 8a16a91a5ceaccfcbd6aaaa56d46828806e460dd194965b3f77bf38f14b942c4
|
||||
F ext/misc/totype.c fa4aedeb07f66169005dffa8de3b0a2b621779fd44f85c103228a42afa71853b
|
||||
F ext/misc/uint.c 5870865fb5f6153db18db443f3ecdcdb17a06567ee47ecd9fd26e3ec7e5f6ce8
|
||||
F ext/misc/unionvtab.c 36237f0607ca954ac13a4a0e2d2ac40c33bc6e032a5f55f431713061ef1625f9
|
||||
F ext/misc/urifuncs.c f71360d14fa9e7626b563f1f781c6148109462741c5235ac63ae0f8917b9c751
|
||||
F ext/misc/uuid.c 5bb2264c1b64d163efa46509544fd7500cb8769cb7c16dd52052da8d961505cf
|
||||
@@ -453,7 +455,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk 7ce055f3df31a4f7d21e38f493f907c21db1f673863a573e231f55e2ab005023
|
||||
F main.mk 0c20162946c82e216ae3abab6334d52f1c9b09035c13619ade404b5e7fe3ce21
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -472,18 +474,18 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
||||
F src/backup.c 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||
F src/btree.c 79ce96ab39fd2fc21ff00d03913587d5a08280a9eb081a08d0ffa9fa26f4f6fb
|
||||
F src/btree.h 6111552f19ed7a40f029cf4b33badc6fef9880314fffd80a945f0b7f43ab7471
|
||||
F src/btreeInt.h dee1a1d0c621524e006bb260bd6b66d5d1867da6fe38cba9ad7b6a9bb9c0c175
|
||||
F src/btree.c 02376eb7d49ccf31b53c2504f045ad74687c142a5c15ca837516e59e737867dc
|
||||
F src/btree.h 32672fa1aa74a7e9ab3aae822f94ffc8e732b1eb005988dc2283f91dc7573398
|
||||
F src/btreeInt.h 887cdd2ea7f4a65143074a8a7c8928b0546f8c18dda3c06a408ce7992cbab0c0
|
||||
F src/build.c ec6c0bda1e43ef55e5f5121a77ba19fac51fc6585f95ce2da795bcedcf6e8f36
|
||||
F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 6a77ec9e0eb87aea929e002c816298907e337094a7b556898ae2d1e6be209f90
|
||||
F src/ctime.c 6892999ee100bd72b64f84dd7a8f737817d72872648705fbf8ed9575e1f1dd1a
|
||||
F src/date.c b29b349d277e3d579dcc295b24c0a2caed83fd8f090a9f7cbe6070c0fd662384
|
||||
F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a
|
||||
F src/dbstat.c 793deaf88a0904f88285d93d6713c636d55ede0ffd9f08d10f4ea825531d367f
|
||||
F src/delete.c 11000121c4281c0bce4e41db29addfaea0038eaa127ece02557c9207bc3e541d
|
||||
F src/expr.c b292bdecd64cd695109ceaa3c810f8b41f202368c75adb9ea680a875df5b0308
|
||||
F src/expr.c d1e1d42cbdec08bb867a1ab43a59b401d82ff2bc88bdcb4af20e479a5facb6d8
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 4b575423b0a5d4898b1a7868ce985cf1a8ad91c741c9abbb108ff02536d20f41
|
||||
F src/func.c f3dcdc0e95509864767c1f0991b19360f969e44177f4e058fd51da9a6154f47e
|
||||
@@ -494,9 +496,9 @@ F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 8e4211d04eb460c0694d486c6ba1c068d468c6f653c3f237869a802ad82854de
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c b179df50e6e8bb0c36c149e95d958d49bd8c6c7469e59c01b53d164360bc6c32
|
||||
F src/main.c 2e076b6dc1f8ab69c7fc604e8af88ab138a64c0616826361e254cee55bcba4e8
|
||||
F src/malloc.c cabfef0d725e04c8abfe0231a556ed8b78bf329dcc3fddbf903f6cdcd53cf4e6
|
||||
F src/loadext.c 421310045bd78afefb772294a99e50f37d87ae578786a6169074e6291e30d969
|
||||
F src/main.c 7e07ff5ec447451d28398d528fda25c272f86cce67bc59a9846ee5bdfb23e1d9
|
||||
F src/malloc.c a3e13b001f988ecec6bdb90c0ea8912c8c786e623724d7098da623d8d01d19b1
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
|
||||
@@ -515,10 +517,10 @@ F src/os.c 669cc3839cc35d20f81faf0be1ab6d4581cea35e9d8f3a9d48a98d6571f7c285
|
||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||
F src/os_unix.c 06593ba4bdfae42b30a897b3b4e59abb88a11d50dd0cad39003da955d822b8d1
|
||||
F src/os_unix.c 7ef8b60222558a373d89c18d0c3bc44365b45273a528183d40bec5bb76ce23fc
|
||||
F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c a71ffd145f55e28cbdc1bdabb5e6bef063da428a6c0de3c3a36e9a0c41d4c8c0
|
||||
F src/pager.c 52cee2f72710be47b5b13ff66b339ca3855e5bc48e92a94114d2affedc70041f
|
||||
F src/pager.h 3b33619a90180e0874c7eca31d6f6ceb464d9322c6fb4e9a7bbb318c8a17bdb3
|
||||
F src/parse.y c8eff38606f443d5ba245263fa7abc05e4116d95656e050c4b78e9bfbf931add
|
||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||
@@ -531,11 +533,11 @@ F src/printf.c 9be6945837c839ba57837b4bc3af349eba630920fa5532aa518816defe42a7d4
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c d36a2b1639e1c33d7b508abfd3452a63e7fd81737f6f3940bfef085fca6f21f4
|
||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||
F src/select.c ab4eb1aee1bd066feea5b6eff264220ae54459019654264e9f688368a7d0c0b5
|
||||
F src/shell.c.in cf7d6140c33859a86188aa52093dfa5d4e4d9ce32ecf1d588a127cb0a8f6f96f
|
||||
F src/sqlite.h.in cc7d0949ac32bb68ed97acdb3e7ae91cd413a24d32d6ff049ef8308d620a4367
|
||||
F src/select.c c310de94bf67315054587c18a16e7a3e3dc3a98dc79168f0c2b776548d43f6cd
|
||||
F src/shell.c.in cf2d24f54412c06e5fb34af7fabc748651125e1dceac29b740e91f06d23447b6
|
||||
F src/sqlite.h.in b20d5dc52765ff82f3701395a7e670611ddf138ee0ae84482452ad3a0b5f24b5
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 9c5269260409eb3275324ccace6a13a96f4ad330c708415f70ca6097901ff4ee
|
||||
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
|
||||
F src/sqliteInt.h 0f3848c46310d197246003f052985b72d1cdbfc0b31e069db76cb5231062fa1d
|
||||
F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032
|
||||
F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
|
||||
@@ -602,16 +604,17 @@ F src/update.c 3eb778c42155d944377a4ee5e440b04520f07094804ed6ce63d2528f619614d9
|
||||
F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
|
||||
F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7
|
||||
F src/util.c 3b6cedf7a0c69bd6e1acce832873952d416212d6293b18d03064e07d7a9b5118
|
||||
F src/vacuum.c 813b510ba887fee6492bcb11f2bf77d7eb58b232b83649136372e0a2fc17f4b9
|
||||
F src/vacuum.c f25d3b39681595e321a8a4e7fca3e5971cb14a401213d0742c9bf7d4ce8c2a1a
|
||||
F src/vdbe.c 972999395eee88702091fb5d50cf4effd07889c371807d222a7f517388e6378e
|
||||
F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9
|
||||
F src/vdbeInt.h 0b728ee662862a38b1912af741e2ac64f524de3c77aa86cf4306c42bdcd9de59
|
||||
F src/vdbe.h 07b8c636a87df8b6e58f29d6badd7f10d5844353deff1d7c88ed1c2bfe3bbd35
|
||||
F src/vdbeInt.h 571413068b5ac07e2ed8ca7a02fa529622fd5455ae6981498376e5e492d2e5ef
|
||||
F src/vdbeapi.c d176ee7251d5344de7bb2a0d2dd0fe536834e5843d9bc2389e0f5cdcd5374141
|
||||
F src/vdbeaux.c 8349559e72bf0cfa2258b1159b004ec4d1717a054d2e1829c8cc897c32da8752
|
||||
F src/vdbeaux.c 319a6e44cff0e8ba710a8374778043609d11cf82cb4ab2ba0a80dde52e607a08
|
||||
F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1
|
||||
F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22
|
||||
F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df
|
||||
F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0
|
||||
F src/vdbevtab.c 8094dfc28dad82d60a1c832020a1b201a5381dc185c14638affc6d4e9d54c653
|
||||
F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c ea8dad28bb0e2b85ac1ab7618968687ff5fd522af8a1a38d6960ec176ebc8ee6
|
||||
@@ -820,7 +823,7 @@ F test/descidx1.test edc8adee58d491b06c7157c50364eaf1c3605c9c19f8093cb1ea2b6184f
|
||||
F test/descidx2.test a0ba347037ff3b811f4c6ceca5fd0f9d5d72e74e59f2d9de346a9d2f6ad78298
|
||||
F test/descidx3.test 953c831df7ea219c73826dfbf2f6ee02d95040725aa88ccb4fa43d1a1999b926
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 8b6c652f0b2d477f0830884736f2a1cd2e8f7fc10a04aa6d571a401fa13ed88b
|
||||
F test/distinct.test e7d0cf371944dd0cbedff86420744e2f1ea2b528156451c97eb6ff41a99b9236
|
||||
F test/distinct2.test 11b0594c932098e969d084ba45ab81d5040f4d4e766db65d49146705a305ed98
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_blobbytes.test 439a945953b35cb6948a552edaec4dc31fd70a05
|
||||
@@ -945,7 +948,7 @@ F test/fts3conf.test c84bbaec81281c1788aa545ac6e78a6bd6cde2bdbbce2da261690e3659f
|
||||
F test/fts3corrupt.test 79a32ffdcd5254e2f7fa121d9656e61949ad049c3c6554229911b7ceac37c9c6
|
||||
F test/fts3corrupt2.test bf55c3fa0b0dc8ea1c0fe5543623bd27714585da6a129038fd6999fe3b0d25f3
|
||||
F test/fts3corrupt3.test 0d5b69a0998b4adf868cc301fc78f3d0707745f1d984ce044c205cdb764b491f
|
||||
F test/fts3corrupt4.test e8ad49403179cbf714b6b669d2e0f9234ae95f4ca258a253b0f29ce28c1b027c
|
||||
F test/fts3corrupt4.test 6a1331bb51dc27acc063d26e0f1b610863b56a833ee54fa32767d17cf96bda4a
|
||||
F test/fts3corrupt5.test 0549f85ec4bd22e992f645f13c59b99d652f2f5e643dac75568bfd23a6db7ed5
|
||||
F test/fts3cov.test 7eacdbefd756cfa4dc2241974e3db2834e9b372ca215880e00032222f32194cf
|
||||
F test/fts3d.test 2bd8c97bcb9975f2334147173b4872505b6a41359a4f9068960a36afe07a679f
|
||||
@@ -966,7 +969,7 @@ F test/fts3fuzz001.test e3c7b0ce9b04cc02281dcc96812a277f02df03cd7dc082055d87e11e
|
||||
F test/fts3join.test 949b4f5ae3ae9cc2423cb865d711e32476bdb205ab2be923fdf48246e4a44166
|
||||
F test/fts3malloc.test b0e4c133b8d61d4f6d112d8110f8320e9e453ef6
|
||||
F test/fts3matchinfo.test aa66cc50615578b30f6df9984819ae5b702511cf8a94251ec7c594096a703a4a
|
||||
F test/fts3misc.test 236f37a57d97fa1b7e0a4303aab7e02da87a9818c106e513ae88af76f25ace4a
|
||||
F test/fts3misc.test 9ec15e7c0b5831a6353bd4c46bf3acdf1360eda5d9f396f667db4d05bcf92ecf
|
||||
F test/fts3near.test 7e3354d46f155a822b59c0e957fd2a70c1d7e905
|
||||
F test/fts3offsets.test b85fd382abdc78ebce721d8117bd552dfb75094c
|
||||
F test/fts3prefix.test fa794eaab0bdae466494947b0b153d7844478ab2
|
||||
@@ -980,7 +983,7 @@ F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
|
||||
F test/fts3tok1.test a663f4cac22a9505400bc22aacb818d7055240409c28729669ea7d4cc2120d15
|
||||
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
|
||||
F test/fts3varint.test 0b84a3fd4eba8a39f3687523804d18f3b322e6d4539a55bf342079c3614f2ada
|
||||
F test/fts4aa.test 9857f939f5aeb6cc4c143e74cf1cfe07ac87972240ac26d3a0100e36d02f4359
|
||||
F test/fts4aa.test 0e6bfd6a81695a39b23e448dda25d864e63dda75bde6949c45ddc95426c6c3f5
|
||||
F test/fts4check.test 6259f856604445d7b684c9b306b2efb6346834c3f50e8fc4a59a2ca6d5319ad0
|
||||
F test/fts4content.test 73bbb123420d2c46ef2fb3b24761e9acdb78b0877179d3a5d7d57aada08066f6
|
||||
F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01
|
||||
@@ -1092,7 +1095,7 @@ F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/istrue.test 75327829744e65cc8700e69340b8e6c192e10e39dfae7ccb0e970d3c4f49090a
|
||||
F test/join.test bca044589e94bb466e4c1e91fb6fecdc3f3326ca6b3f590f555f1958156eb321
|
||||
F test/join2.test 659bc6193f5c3fe20fa444dd2c91713db8c33e376b098b860644e175e87b8dbc
|
||||
F test/join2.test 7d24d095ab88d3910228d53a3b548b7baf2e0e7d8aac6731a273e300e1b34b61
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 3a96dc62f0b45402d7207e22d1993fe0c2fce1c57644a11439891dd62b990eb7
|
||||
@@ -1333,7 +1336,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 1796b7f76d09ffd2b2dc0ff5ad89428e9892f237d4f4e33ef2278f064a2d94a4
|
||||
F test/shell1.test 5bd10014ec494744f5e966a1521334e9d612119a0afcfa5251684a4e1f2ffc66
|
||||
F test/shell2.test e242a9912f44f4c23c3d1d802a83e934e84c853b
|
||||
F test/shell3.test ac8c2b744014c3e9a0e26bfd829ab65f00923dc1a91ffd044863e9423cc91494
|
||||
F test/shell4.test 1c6aef11daaa2d6830acaba3ac9cbec93fbc1c3d5530743a637f39b3987d08ce
|
||||
@@ -1712,7 +1715,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test a2874062140ed4aba9ffae76e6190a3df6fc73d1373fdfa8fd632945082a5364
|
||||
F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a
|
||||
F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b
|
||||
F test/whereL.test d19499a39c9e3e5a74460778b009558d328c8a230c0e6825c9996c9adff89058
|
||||
F test/whereL.test e05cedc9389c6f09ad55bd5999a3fddccebec90672fb989433c145dcdaf26996
|
||||
F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864
|
||||
F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3
|
||||
F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0
|
||||
@@ -1798,7 +1801,7 @@ F tool/mkshellc.tcl 70a9978e363b0f3280ca9ce1c46d72563ff479c1930a12a7375e3881b732
|
||||
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
|
||||
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
|
||||
F tool/mksqlite3c-noext.tcl 4f7cfef5152b0c91920355cbfc1d608a4ad242cb819f1aea07f6d0274f584a7f
|
||||
F tool/mksqlite3c.tcl 5fed3d75069d8f66f202d3b5200b0cea4aa7108481acd06732a06fdd42eb83a2
|
||||
F tool/mksqlite3c.tcl 3ab95bcf7b765f9d6d99cbeb8c4f150b38b0bb1f001ffac688f2ad02ebce2123
|
||||
F tool/mksqlite3h.tcl 080873e3856eceb9d289a08a00c4b30f875ea3feadcbece796bd509b1532792c
|
||||
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
|
||||
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
|
||||
@@ -1817,7 +1820,7 @@ F tool/showshm.c a0ab6ec32dd1f11218ca2a4018f8fb875b59414801ab8ceed8b2e69b7b45a80
|
||||
F tool/showstat4.c 0682ebea7abf4d3657f53c4a243f2e7eab48eab344ed36a94bb75dcd19a5c2a1
|
||||
F tool/showwal.c ad9d768f96ca6199ad3a8c9562d679680bd032dd01204ea3e5ea6fb931d81847
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/spaceanal.tcl 4bfd19aad7eb3ce0372ef0255f58035e0bba4ff5e9acfd763a10c6fb365c8dec
|
||||
F tool/spaceanal.tcl c161d838825d0242317c7cc13b1eb2126f8cec031950ef31114d42732cb2674e
|
||||
F tool/speed-check.sh 2b042d703a9472f08c3b13be27afac658426f8e4fc87cd2d575953fda86f08d1
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c ecb6542862151c3e6509bbc00509b234562ae81e
|
||||
@@ -1860,7 +1863,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 10306118e8591e727af477a1a15d136852d21170e645bd0e75f7c88346b037d7
|
||||
R 979d0103f7b3acef2369409e370d6fa7
|
||||
U mistachkin
|
||||
Z 484824f16820465db78cbfdb9a5d496b
|
||||
P 96dfc71ea599702ef38b60952d03e95dce5a8c534cd943e076e9c76b00e61e65
|
||||
R 8a6312f86dfd0f2dc1b9dbd32625eb27
|
||||
U drh
|
||||
Z 054131aab304a488c76322b7f6a162fc
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
85d3dc8c50d8dbb8eac1956e8976e861d3b671e03355ca9257060fa3dca51cc4
|
||||
baa720e4a88f268ed95337daab5f434fd3263b00f09101cddc6424765bf3b722
|
||||
+10
-6
@@ -2857,8 +2857,11 @@ int sqlite3BtreeSetPagerFlags(
|
||||
int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve, int iFix){
|
||||
int rc = SQLITE_OK;
|
||||
BtShared *pBt = p->pBt;
|
||||
assert( nReserve>=-1 && nReserve<=255 );
|
||||
assert( nReserve>=-1 && nReserve<=254 );
|
||||
sqlite3BtreeEnter(p);
|
||||
if( nReserve>=0 ){
|
||||
pBt->nReserveWanted = nReserve + 1;
|
||||
}
|
||||
if( pBt->btsFlags & BTS_PAGESIZE_FIXED ){
|
||||
sqlite3BtreeLeave(p);
|
||||
return SQLITE_READONLY;
|
||||
@@ -2911,14 +2914,15 @@ int sqlite3BtreeGetReserveNoMutex(Btree *p){
|
||||
** are intentually left unused. This is the "reserved" space that is
|
||||
** sometimes used by extensions.
|
||||
**
|
||||
** If SQLITE_HAS_MUTEX is defined then the number returned is the
|
||||
** greater of the current reserved space and the maximum requested
|
||||
** reserve space.
|
||||
** The value returned is the larger of the current reserve size and
|
||||
** the latest reserve size requested by SQLITE_FILECTRL_RESERVE_BYTES.
|
||||
** The amount of reserve can only grow - never shrink.
|
||||
*/
|
||||
int sqlite3BtreeGetOptimalReserve(Btree *p){
|
||||
int sqlite3BtreeGetRequestedReserve(Btree *p){
|
||||
int n;
|
||||
sqlite3BtreeEnter(p);
|
||||
n = sqlite3BtreeGetReserveNoMutex(p);
|
||||
n = ((int)p->pBt->nReserveWanted) - 1;
|
||||
if( n<0 ) n = sqlite3BtreeGetReserveNoMutex(p);
|
||||
sqlite3BtreeLeave(p);
|
||||
return n;
|
||||
}
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ int sqlite3BtreeGetPageSize(Btree*);
|
||||
int sqlite3BtreeMaxPageCount(Btree*,int);
|
||||
u32 sqlite3BtreeLastPage(Btree*);
|
||||
int sqlite3BtreeSecureDelete(Btree*,int);
|
||||
int sqlite3BtreeGetOptimalReserve(Btree*);
|
||||
int sqlite3BtreeGetRequestedReserve(Btree*);
|
||||
int sqlite3BtreeGetReserveNoMutex(Btree *p);
|
||||
int sqlite3BtreeSetAutoVacuum(Btree *, int);
|
||||
int sqlite3BtreeGetAutoVacuum(Btree *);
|
||||
|
||||
@@ -417,6 +417,7 @@ struct BtShared {
|
||||
#endif
|
||||
u8 inTransaction; /* Transaction state */
|
||||
u8 max1bytePayload; /* Maximum first byte of cell for a 1-byte payload */
|
||||
u8 nReserveWanted; /* 1 more than desired number of extra bytes per page */
|
||||
u16 btsFlags; /* Boolean parameters. See BTS_* macros below */
|
||||
u16 maxLocal; /* Maximum local payload in non-LEAFDATA tables */
|
||||
u16 minLocal; /* Minimum local payload in non-LEAFDATA tables */
|
||||
|
||||
@@ -193,6 +193,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|
||||
"ENABLE_BATCH_ATOMIC_WRITE",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_BYTECODE_VTAB
|
||||
"ENABLE_BYTECODE_VTAB",
|
||||
#endif
|
||||
#if SQLITE_ENABLE_CEROD
|
||||
"ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD),
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -45,7 +45,7 @@ char sqlite3TableColumnAffinity(Table *pTab, int iCol){
|
||||
char sqlite3ExprAffinity(const Expr *pExpr){
|
||||
int op;
|
||||
while( ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
|
||||
pExpr = pExpr->pLeft;
|
||||
assert( pExpr!=0 );
|
||||
}
|
||||
@@ -112,7 +112,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){
|
||||
*/
|
||||
Expr *sqlite3ExprSkipCollate(Expr *pExpr){
|
||||
while( pExpr && ExprHasProperty(pExpr, EP_Skip) ){
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
return pExpr;
|
||||
@@ -131,7 +131,7 @@ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
|
||||
assert( pExpr->op==TK_FUNCTION );
|
||||
pExpr = pExpr->x.pList->a[0].pExpr;
|
||||
}else{
|
||||
assert( pExpr->op==TK_COLLATE );
|
||||
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_IF_NULL_ROW );
|
||||
pExpr = pExpr->pLeft;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -477,8 +477,17 @@ static const sqlite3_api_routines sqlite3Apis = {
|
||||
/* Version 3.32.0 and later */
|
||||
sqlite3_create_filename,
|
||||
sqlite3_free_filename,
|
||||
sqlite3_database_file_object,
|
||||
};
|
||||
|
||||
/* True if x is the directory separator character
|
||||
*/
|
||||
#if SQLITE_OS_WIN
|
||||
# define DirSep(X) ((X)=='/'||(X)=='\\')
|
||||
#else
|
||||
# define DirSep(X) ((X)=='/')
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Attempt to load an SQLite extension library contained in the file
|
||||
** zFile. The entry point is zProc. zProc may be 0 in which case a
|
||||
@@ -580,7 +589,7 @@ static int sqlite3LoadExtension(
|
||||
return SQLITE_NOMEM_BKPT;
|
||||
}
|
||||
memcpy(zAltEntry, "sqlite3_", 8);
|
||||
for(iFile=ncFile-1; iFile>=0 && zFile[iFile]!='/'; iFile--){}
|
||||
for(iFile=ncFile-1; iFile>=0 && !DirSep(zFile[iFile]); iFile--){}
|
||||
iFile++;
|
||||
if( sqlite3_strnicmp(zFile+iFile, "lib", 3)==0 ) iFile += 3;
|
||||
for(iEntry=8; (c = zFile[iFile])!=0 && c!='.'; iFile++){
|
||||
|
||||
+13
-14
@@ -3358,6 +3358,12 @@ static int openDatabase(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
if( !db->mallocFailed && rc==SQLITE_OK){
|
||||
rc = sqlite3VdbeBytecodeVtabInit(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_INTERNAL_FUNCTIONS
|
||||
/* Testing use only!!! The -DSQLITE_ENABLE_INTERNAL_FUNCTIONS=1 compile-time
|
||||
** option gives access to internal functions by default.
|
||||
@@ -3843,6 +3849,13 @@ int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, void *pArg){
|
||||
}else if( op==SQLITE_FCNTL_DATA_VERSION ){
|
||||
*(unsigned int*)pArg = sqlite3PagerDataVersion(pPager);
|
||||
rc = SQLITE_OK;
|
||||
}else if( op==SQLITE_FCNTL_RESERVE_BYTES ){
|
||||
int iNew = *(int*)pArg;
|
||||
*(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree);
|
||||
if( iNew>=0 && iNew<=254 ){
|
||||
sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0);
|
||||
}
|
||||
rc = SQLITE_OK;
|
||||
}else{
|
||||
rc = sqlite3OsFileControl(fd, op, pArg);
|
||||
}
|
||||
@@ -4059,20 +4072,6 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_RESERVE, sqlite3 *db, int N)
|
||||
**
|
||||
** Set the nReserve size to N for the main database on the database
|
||||
** connection db.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_RESERVE: {
|
||||
sqlite3 *db = va_arg(ap, sqlite3*);
|
||||
int x = va_arg(ap,int);
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
sqlite3BtreeSetPageSize(db->aDb[0].pBt, 0, x, 0);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, sqlite3 *db, int N)
|
||||
**
|
||||
** Enable or disable various optimizations for testing purposes. The
|
||||
|
||||
+4
-4
@@ -111,7 +111,7 @@ sqlite3_int64 sqlite3_soft_heap_limit64(sqlite3_int64 n){
|
||||
}
|
||||
mem0.alarmThreshold = n;
|
||||
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
mem0.nearlyFull = (n>0 && n<=nUsed);
|
||||
AtomicStore(&mem0.nearlyFull, n>0 && n<=nUsed);
|
||||
sqlite3_mutex_leave(mem0.mutex);
|
||||
excess = sqlite3_memory_used() - n;
|
||||
if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
|
||||
@@ -179,7 +179,7 @@ int sqlite3MallocInit(void){
|
||||
** sqlite3_soft_heap_limit().
|
||||
*/
|
||||
int sqlite3HeapNearlyFull(void){
|
||||
return mem0.nearlyFull;
|
||||
return AtomicLoad(&mem0.nearlyFull);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -243,7 +243,7 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
if( mem0.alarmThreshold>0 ){
|
||||
sqlite3_int64 nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
if( nUsed >= mem0.alarmThreshold - nFull ){
|
||||
mem0.nearlyFull = 1;
|
||||
AtomicStore(&mem0.nearlyFull, 1);
|
||||
sqlite3MallocAlarm(nFull);
|
||||
if( mem0.hardLimit ){
|
||||
nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED);
|
||||
@@ -253,7 +253,7 @@ static void mallocWithAlarm(int n, void **pp){
|
||||
}
|
||||
}
|
||||
}else{
|
||||
mem0.nearlyFull = 0;
|
||||
AtomicStore(&mem0.nearlyFull, 0);
|
||||
}
|
||||
}
|
||||
p = sqlite3GlobalConfig.m.xMalloc(nFull);
|
||||
|
||||
+1
-1
@@ -3685,7 +3685,7 @@ static int openDirectory(const char *zFilename, int *pFd){
|
||||
if( zDirname[0]!='/' ) zDirname[0] = '.';
|
||||
zDirname[1] = 0;
|
||||
}
|
||||
fd = robust_open(zDirname, O_RDONLY|O_BINARY|O_NOFOLLOW, 0);
|
||||
fd = robust_open(zDirname, O_RDONLY|O_BINARY, 0);
|
||||
if( fd>=0 ){
|
||||
OSTRACE(("OPENDIR %-3d %s\n", fd, zDirname));
|
||||
}
|
||||
|
||||
+20
-1
@@ -2536,9 +2536,12 @@ static int pager_delmaster(Pager *pPager, const char *zMaster){
|
||||
/* One of the journals pointed to by the master journal exists.
|
||||
** Open it and check if it points at the master journal. If
|
||||
** so, return without deleting the master journal file.
|
||||
** NB: zJournal is really a MAIN_JOURNAL. But call it a
|
||||
** MASTER_JOURNAL here so that the VFS will not send the zJournal
|
||||
** name into sqlite3_database_file_object().
|
||||
*/
|
||||
int c;
|
||||
int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL);
|
||||
int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MASTER_JOURNAL);
|
||||
rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto delmaster_out;
|
||||
@@ -4742,6 +4745,7 @@ int sqlite3PagerOpen(
|
||||
** Database file handle (pVfs->szOsFile bytes)
|
||||
** Sub-journal file handle (journalFileSize bytes)
|
||||
** Main journal file handle (journalFileSize bytes)
|
||||
** Ptr back to the Pager (sizeof(Pager*) bytes)
|
||||
** \0\0\0\0 database prefix (4 bytes)
|
||||
** Database file name (nPathname+1 bytes)
|
||||
** URI query parameters (nUriByte bytes)
|
||||
@@ -4781,6 +4785,7 @@ int sqlite3PagerOpen(
|
||||
ROUND8(pcacheSize) + /* PCache object */
|
||||
ROUND8(pVfs->szOsFile) + /* The main db file */
|
||||
journalFileSize * 2 + /* The two journal files */
|
||||
sizeof(pPager) + /* Space to hold a pointer */
|
||||
4 + /* Database prefix */
|
||||
nPathname + 1 + /* database filename */
|
||||
nUriByte + /* query parameters */
|
||||
@@ -4801,6 +4806,7 @@ int sqlite3PagerOpen(
|
||||
pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
|
||||
pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
|
||||
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
|
||||
memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
|
||||
|
||||
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
|
||||
pPtr += 4; /* Skip zero prefix */
|
||||
@@ -5001,6 +5007,19 @@ act_like_temp_file:
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the sqlite3_file for the main database given the name
|
||||
** of the corresonding WAL or Journal name as passed into
|
||||
** xOpen.
|
||||
*/
|
||||
sqlite3_file *sqlite3_database_file_object(const char *zName){
|
||||
Pager *pPager;
|
||||
while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
|
||||
zName--;
|
||||
}
|
||||
pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
|
||||
return pPager->fd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -3498,6 +3498,7 @@ static Expr *substExpr(
|
||||
ifNullRow.op = TK_IF_NULL_ROW;
|
||||
ifNullRow.pLeft = pCopy;
|
||||
ifNullRow.iTable = pSubst->iNewTable;
|
||||
ifNullRow.flags = EP_Skip;
|
||||
pCopy = &ifNullRow;
|
||||
}
|
||||
testcase( ExprHasProperty(pCopy, EP_Subquery) );
|
||||
|
||||
+111
-39
@@ -1010,6 +1010,7 @@ INCLUDE ../ext/misc/fileio.c
|
||||
INCLUDE ../ext/misc/completion.c
|
||||
INCLUDE ../ext/misc/appendvfs.c
|
||||
INCLUDE ../ext/misc/memtrace.c
|
||||
INCLUDE ../ext/misc/uint.c
|
||||
#ifdef SQLITE_HAVE_ZLIB
|
||||
INCLUDE ../ext/misc/zipfile.c
|
||||
INCLUDE ../ext/misc/sqlar.c
|
||||
@@ -1106,6 +1107,7 @@ struct ShellState {
|
||||
unsigned mxProgress; /* Maximum progress callbacks before failing */
|
||||
unsigned flgProgress; /* Flags for the progress callback */
|
||||
unsigned shellFlgs; /* Various flags */
|
||||
unsigned priorShFlgs; /* Saved copy of flags */
|
||||
sqlite3_int64 szMax; /* --maxsize argument to .open */
|
||||
char *zDestTable; /* Name of destination table when MODE_Insert */
|
||||
char *zTempFile; /* Temporary file that might need deleting */
|
||||
@@ -1406,11 +1408,13 @@ edit_func_end:
|
||||
*/
|
||||
static void outputModePush(ShellState *p){
|
||||
p->modePrior = p->mode;
|
||||
p->priorShFlgs = p->shellFlgs;
|
||||
memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator));
|
||||
memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator));
|
||||
}
|
||||
static void outputModePop(ShellState *p){
|
||||
p->mode = p->modePrior;
|
||||
p->shellFlgs = p->priorShFlgs;
|
||||
memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator));
|
||||
memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator));
|
||||
}
|
||||
@@ -3154,6 +3158,7 @@ static int shell_exec(
|
||||
const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3);
|
||||
int iEqpId = sqlite3_column_int(pExplain, 0);
|
||||
int iParentId = sqlite3_column_int(pExplain, 1);
|
||||
if( zEQPLine==0 ) zEQPLine = "";
|
||||
if( zEQPLine[0]=='-' ) eqp_render(pArg);
|
||||
eqp_append(pArg, iEqpId, iParentId, zEQPLine);
|
||||
}
|
||||
@@ -3579,11 +3584,13 @@ static const char *(azHelp[]) = {
|
||||
#endif
|
||||
" trigger Like \"full\" but also show trigger bytecode",
|
||||
".excel Display the output of next command in spreadsheet",
|
||||
" --bom Put a UTF8 byte-order mark on intermediate file",
|
||||
".exit ?CODE? Exit this program with return-code CODE",
|
||||
".expert EXPERIMENTAL. Suggest indexes for queries",
|
||||
".explain ?on|off|auto? Change the EXPLAIN formatting mode. Default: auto",
|
||||
".filectrl CMD ... Run various sqlite3_file_control() operations",
|
||||
" Run \".filectrl\" with no arguments for details",
|
||||
" --schema SCHEMA Use SCHEMA instead of \"main\"",
|
||||
" --help Show CMD details",
|
||||
".fullschema ?--indent? Show schema and the content of sqlite_stat tables",
|
||||
".headers on|off Turn display of headers on or off",
|
||||
".help ?-all? ?PATTERN? Show help text for PATTERN",
|
||||
@@ -3630,11 +3637,11 @@ static const char *(azHelp[]) = {
|
||||
" tabs Tab-separated values",
|
||||
" tcl TCL list elements",
|
||||
".nullvalue STRING Use STRING in place of NULL values",
|
||||
".once (-e|-x|FILE) Output for the next SQL command only to FILE",
|
||||
".once ?OPTIONS? ?FILE? Output for the next SQL command only to FILE",
|
||||
" If FILE begins with '|' then open as a pipe",
|
||||
" Other options:",
|
||||
" -e Invoke system text editor",
|
||||
" -x Open in a spreadsheet",
|
||||
" --bom Put a UTF8 byte-order mark at the beginning",
|
||||
" -e Send output to the system text editor",
|
||||
" -x Send output as CSV to a spreadsheet (same as \".excel\")",
|
||||
#ifdef SQLITE_DEBUG
|
||||
".oom [--repeat M] [N] Simulate an OOM error on the N-th allocation",
|
||||
#endif
|
||||
@@ -3651,7 +3658,11 @@ static const char *(azHelp[]) = {
|
||||
" --readonly Open FILE readonly",
|
||||
" --zip FILE is a ZIP archive",
|
||||
".output ?FILE? Send output to FILE or stdout if FILE is omitted",
|
||||
" If FILE begins with '|' then open it as a pipe.",
|
||||
" If FILE begins with '|' then open it as a pipe.",
|
||||
" Options:",
|
||||
" --bom Prefix output with a UTF8 byte-order mark",
|
||||
" -e Send output to the system text editor",
|
||||
" -x Send output as CSV to a spreadsheet",
|
||||
".parameter CMD ... Manage SQL parameter bindings",
|
||||
" clear Erase all bindings",
|
||||
" init Initialize the TEMP table that holds bindings",
|
||||
@@ -3771,6 +3782,7 @@ static int showHelp(FILE *out, const char *zPattern){
|
||||
|| zPattern[0]=='0'
|
||||
|| strcmp(zPattern,"-a")==0
|
||||
|| strcmp(zPattern,"-all")==0
|
||||
|| strcmp(zPattern,"--all")==0
|
||||
){
|
||||
/* Show all commands, but only one line per command */
|
||||
if( zPattern==0 ) zPattern = "";
|
||||
@@ -4252,6 +4264,7 @@ static void open_db(ShellState *p, int openFlags){
|
||||
sqlite3_fileio_init(p->db, 0, 0);
|
||||
sqlite3_shathree_init(p->db, 0, 0);
|
||||
sqlite3_completion_init(p->db, 0, 0);
|
||||
sqlite3_uint_init(p->db, 0, 0);
|
||||
#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_ENABLE_DBPAGE_VTAB)
|
||||
sqlite3_dbdata_init(p->db, 0, 0);
|
||||
#endif
|
||||
@@ -4971,11 +4984,15 @@ static void output_reset(ShellState *p){
|
||||
zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile);
|
||||
if( system(zCmd) ){
|
||||
utf8_printf(stderr, "Failed: [%s]\n", zCmd);
|
||||
}else{
|
||||
/* Give the start/open/xdg-open command some time to get
|
||||
** going before we continue, and potential delete the
|
||||
** p->zTempFile data file out from under it */
|
||||
sqlite3_sleep(2000);
|
||||
}
|
||||
sqlite3_free(zCmd);
|
||||
outputModePop(p);
|
||||
p->doXdgOpen = 0;
|
||||
sqlite3_sleep(100);
|
||||
}
|
||||
#endif /* !defined(SQLITE_NOHAVE_SYSTEM) */
|
||||
}
|
||||
@@ -5051,12 +5068,7 @@ static int shell_dbinfo_command(ShellState *p, int nArg, char **azArg){
|
||||
"SELECT data FROM sqlite_dbpage(?1) WHERE pgno=1",
|
||||
-1, &pStmt, 0);
|
||||
if( rc ){
|
||||
if( !sqlite3_compileoption_used("ENABLE_DBPAGE_VTAB") ){
|
||||
utf8_printf(stderr, "the \".dbinfo\" command requires the "
|
||||
"-DSQLITE_ENABLE_DBPAGE_VTAB compile-time options\n");
|
||||
}else{
|
||||
utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
|
||||
}
|
||||
utf8_printf(stderr, "error: %s\n", sqlite3_errmsg(p->db));
|
||||
sqlite3_finalize(pStmt);
|
||||
return 1;
|
||||
}
|
||||
@@ -5265,9 +5277,21 @@ static void newTempFile(ShellState *p, const char *zSuffix){
|
||||
sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile);
|
||||
}
|
||||
if( p->zTempFile==0 ){
|
||||
/* If p->db is an in-memory database then the TEMPFILENAME file-control
|
||||
** will not work and we will need to fallback to guessing */
|
||||
char *zTemp;
|
||||
sqlite3_uint64 r;
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix);
|
||||
zTemp = getenv("TEMP");
|
||||
if( zTemp==0 ) zTemp = getenv("TMP");
|
||||
if( zTemp==0 ){
|
||||
#ifdef _WIN32
|
||||
zTemp = "\\tmp";
|
||||
#else
|
||||
zTemp = "/tmp";
|
||||
#endif
|
||||
}
|
||||
p->zTempFile = sqlite3_mprintf("%s/temp%llx.%s", zTemp, r, zSuffix);
|
||||
}else{
|
||||
p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix);
|
||||
}
|
||||
@@ -7462,6 +7486,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{ "tempfilename", SQLITE_FCNTL_TEMPFILENAME, "" },
|
||||
{ "has_moved", SQLITE_FCNTL_HAS_MOVED, "" },
|
||||
{ "lock_timeout", SQLITE_FCNTL_LOCK_TIMEOUT, "MILLISEC" },
|
||||
{ "reserve_bytes", SQLITE_FCNTL_RESERVE_BYTES, "[N]" },
|
||||
};
|
||||
int filectrl = -1;
|
||||
int iCtrl = -1;
|
||||
@@ -7469,10 +7494,21 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int isOk = 0; /* 0: usage 1: %lld 2: no-result */
|
||||
int n2, i;
|
||||
const char *zCmd = 0;
|
||||
const char *zSchema = 0;
|
||||
|
||||
open_db(p, 0);
|
||||
zCmd = nArg>=2 ? azArg[1] : "help";
|
||||
|
||||
if( zCmd[0]=='-'
|
||||
&& (strcmp(zCmd,"--schema")==0 || strcmp(zCmd,"-schema")==0)
|
||||
&& nArg>=4
|
||||
){
|
||||
zSchema = azArg[2];
|
||||
for(i=3; i<nArg; i++) azArg[i-2] = azArg[i];
|
||||
nArg -= 2;
|
||||
zCmd = azArg[1];
|
||||
}
|
||||
|
||||
/* The argument can optionally begin with "-" or "--" */
|
||||
if( zCmd[0]=='-' && zCmd[1] ){
|
||||
zCmd++;
|
||||
@@ -7514,7 +7550,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_FCNTL_SIZE_LIMIT: {
|
||||
if( nArg!=2 && nArg!=3 ) break;
|
||||
iRes = nArg==3 ? integerValue(azArg[2]) : -1;
|
||||
sqlite3_file_control(p->db, 0, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
|
||||
sqlite3_file_control(p->db, zSchema, SQLITE_FCNTL_SIZE_LIMIT, &iRes);
|
||||
isOk = 1;
|
||||
break;
|
||||
}
|
||||
@@ -7523,7 +7559,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int x;
|
||||
if( nArg!=3 ) break;
|
||||
x = (int)integerValue(azArg[2]);
|
||||
sqlite3_file_control(p->db, 0, filectrl, &x);
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &x);
|
||||
isOk = 2;
|
||||
break;
|
||||
}
|
||||
@@ -7532,7 +7568,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
int x;
|
||||
if( nArg!=2 && nArg!=3 ) break;
|
||||
x = nArg==3 ? booleanValue(azArg[2]) : -1;
|
||||
sqlite3_file_control(p->db, 0, filectrl, &x);
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &x);
|
||||
iRes = x;
|
||||
isOk = 1;
|
||||
break;
|
||||
@@ -7540,7 +7576,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_FCNTL_HAS_MOVED: {
|
||||
int x;
|
||||
if( nArg!=2 ) break;
|
||||
sqlite3_file_control(p->db, 0, filectrl, &x);
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &x);
|
||||
iRes = x;
|
||||
isOk = 1;
|
||||
break;
|
||||
@@ -7548,7 +7584,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
case SQLITE_FCNTL_TEMPFILENAME: {
|
||||
char *z = 0;
|
||||
if( nArg!=2 ) break;
|
||||
sqlite3_file_control(p->db, 0, filectrl, &z);
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &z);
|
||||
if( z ){
|
||||
utf8_printf(p->out, "%s\n", z);
|
||||
sqlite3_free(z);
|
||||
@@ -7556,6 +7592,18 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
isOk = 2;
|
||||
break;
|
||||
}
|
||||
case SQLITE_FCNTL_RESERVE_BYTES: {
|
||||
int x;
|
||||
if( nArg>=3 ){
|
||||
x = atoi(azArg[2]);
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &x);
|
||||
}
|
||||
x = -1;
|
||||
sqlite3_file_control(p->db, zSchema, filectrl, &x);
|
||||
utf8_printf(p->out,"%d\n", x);
|
||||
isOk = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( isOk==0 && iCtrl>=0 ){
|
||||
@@ -8289,42 +8337,66 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
&& (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0))
|
||||
|| (c=='e' && n==5 && strcmp(azArg[0],"excel")==0)
|
||||
){
|
||||
const char *zFile = nArg>=2 ? azArg[1] : "stdout";
|
||||
const char *zFile = 0;
|
||||
int bTxtMode = 0;
|
||||
if( azArg[0][0]=='e' ){
|
||||
/* Transform the ".excel" command into ".once -x" */
|
||||
nArg = 2;
|
||||
azArg[0] = "once";
|
||||
zFile = azArg[1] = "-x";
|
||||
n = 4;
|
||||
int i;
|
||||
int eMode = 0;
|
||||
int bBOM = 0;
|
||||
int bOnce = 0; /* 0: .output, 1: .once, 2: .excel */
|
||||
|
||||
if( c=='e' ){
|
||||
eMode = 'x';
|
||||
bOnce = 2;
|
||||
}else if( strncmp(azArg[0],"once",n)==0 ){
|
||||
bOnce = 1;
|
||||
}
|
||||
if( nArg>2 ){
|
||||
utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
if( n>1 && strncmp(azArg[0], "once", n)==0 ){
|
||||
if( nArg<2 ){
|
||||
raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n");
|
||||
for(i=1; i<nArg; i++){
|
||||
char *z = azArg[i];
|
||||
if( z[0]=='-' ){
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-bom")==0 ){
|
||||
bBOM = 1;
|
||||
}else if( c!='e' && strcmp(z,"-x")==0 ){
|
||||
eMode = 'x'; /* spreadsheet */
|
||||
}else if( c!='e' && strcmp(z,"-e")==0 ){
|
||||
eMode = 'e'; /* text editor */
|
||||
}else{
|
||||
utf8_printf(p->out, "ERROR: unknown option: \"%s\". Usage:\n",
|
||||
azArg[i]);
|
||||
showHelp(p->out, azArg[0]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}else if( zFile==0 ){
|
||||
zFile = z;
|
||||
}else{
|
||||
utf8_printf(p->out,"ERROR: extra parameter: \"%s\". Usage:\n",
|
||||
azArg[i]);
|
||||
showHelp(p->out, azArg[0]);
|
||||
rc = 1;
|
||||
goto meta_command_exit;
|
||||
}
|
||||
}
|
||||
if( zFile==0 ) zFile = "stdout";
|
||||
if( bOnce ){
|
||||
p->outCount = 2;
|
||||
}else{
|
||||
p->outCount = 0;
|
||||
}
|
||||
output_reset(p);
|
||||
if( zFile[0]=='-' && zFile[1]=='-' ) zFile++;
|
||||
#ifndef SQLITE_NOHAVE_SYSTEM
|
||||
if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){
|
||||
if( eMode=='e' || eMode=='x' ){
|
||||
p->doXdgOpen = 1;
|
||||
outputModePush(p);
|
||||
if( zFile[1]=='x' ){
|
||||
if( eMode=='x' ){
|
||||
/* spreadsheet mode. Output as CSV. */
|
||||
newTempFile(p, "csv");
|
||||
ShellClearFlag(p, SHFLG_Echo);
|
||||
p->mode = MODE_Csv;
|
||||
sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma);
|
||||
sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf);
|
||||
}else{
|
||||
/* text editor mode */
|
||||
newTempFile(p, "txt");
|
||||
bTxtMode = 1;
|
||||
}
|
||||
@@ -8343,6 +8415,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->out = stdout;
|
||||
rc = 1;
|
||||
}else{
|
||||
if( bBOM ) fprintf(p->out,"\357\273\277");
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
#endif
|
||||
@@ -8355,6 +8428,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
p->out = stdout;
|
||||
rc = 1;
|
||||
} else {
|
||||
if( bBOM ) fprintf(p->out,"\357\273\277");
|
||||
sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile);
|
||||
}
|
||||
}
|
||||
@@ -9418,7 +9492,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{ "prng_restore", SQLITE_TESTCTRL_PRNG_RESTORE, "" },
|
||||
{ "prng_save", SQLITE_TESTCTRL_PRNG_SAVE, "" },
|
||||
{ "prng_seed", SQLITE_TESTCTRL_PRNG_SEED, "SEED ?db?" },
|
||||
{ "reserve", SQLITE_TESTCTRL_RESERVE, "BYTES-OF-RESERVE"},
|
||||
};
|
||||
int testctrl = -1;
|
||||
int iCtrl = -1;
|
||||
@@ -9471,7 +9544,6 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
|
||||
/* sqlite3_test_control(int, db, int) */
|
||||
case SQLITE_TESTCTRL_OPTIMIZATIONS:
|
||||
case SQLITE_TESTCTRL_RESERVE:
|
||||
if( nArg==3 ){
|
||||
int opt = (int)strtol(azArg[2], 0, 0);
|
||||
rc2 = sqlite3_test_control(testctrl, p->db, opt);
|
||||
|
||||
+92
-26
@@ -299,26 +299,22 @@ typedef sqlite_uint64 sqlite3_uint64;
|
||||
** the [sqlite3] object is successfully destroyed and all associated
|
||||
** resources are deallocated.
|
||||
**
|
||||
** ^If the database connection is associated with unfinalized prepared
|
||||
** statements or unfinished sqlite3_backup objects then sqlite3_close()
|
||||
** will leave the database connection open and return [SQLITE_BUSY].
|
||||
** ^If sqlite3_close_v2() is called with unfinalized prepared statements
|
||||
** and/or unfinished sqlite3_backups, then the database connection becomes
|
||||
** an unusable "zombie" which will automatically be deallocated when the
|
||||
** last prepared statement is finalized or the last sqlite3_backup is
|
||||
** finished. The sqlite3_close_v2() interface is intended for use with
|
||||
** host languages that are garbage collected, and where the order in which
|
||||
** destructors are called is arbitrary.
|
||||
**
|
||||
** Applications should [sqlite3_finalize | finalize] all [prepared statements],
|
||||
** [sqlite3_blob_close | close] all [BLOB handles], and
|
||||
** Ideally, applications should [sqlite3_finalize | finalize] all
|
||||
** [prepared statements], [sqlite3_blob_close | close] all [BLOB handles], and
|
||||
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
|
||||
** with the [sqlite3] object prior to attempting to close the object. ^If
|
||||
** sqlite3_close_v2() is called on a [database connection] that still has
|
||||
** outstanding [prepared statements], [BLOB handles], and/or
|
||||
** [sqlite3_backup] objects then it returns [SQLITE_OK] and the deallocation
|
||||
** of resources is deferred until all [prepared statements], [BLOB handles],
|
||||
** and [sqlite3_backup] objects are also destroyed.
|
||||
** with the [sqlite3] object prior to attempting to close the object.
|
||||
** ^If the database connection is associated with unfinalized prepared
|
||||
** statements, BLOB handlers, and/or unfinished sqlite3_backup objects then
|
||||
** sqlite3_close() will leave the database connection open and return
|
||||
** [SQLITE_BUSY]. ^If sqlite3_close_v2() is called with unfinalized prepared
|
||||
** statements, unclosed BLOB handlers, and/or unfinished sqlite3_backups,
|
||||
** it returns [SQLITE_OK] regardless, but instead of deallocating the database
|
||||
** connection immediately, it marks the database connection as an unusable
|
||||
** "zombie" and makes arrangements to automatically deallocate the database
|
||||
** connection after all prepared statements are finalized, all BLOB handles
|
||||
** are closed, and all backups have finished. The sqlite3_close_v2() interface
|
||||
** is intended for use with host languages that are garbage collected, and
|
||||
** where the order in which destructors are called is arbitrary.
|
||||
**
|
||||
** ^If an [sqlite3] object is destroyed while a transaction is open,
|
||||
** the transaction is automatically rolled back.
|
||||
@@ -507,6 +503,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8))
|
||||
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8))
|
||||
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
|
||||
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<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))
|
||||
@@ -1157,6 +1154,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_DATA_VERSION 35
|
||||
#define SQLITE_FCNTL_SIZE_LIMIT 36
|
||||
#define SQLITE_FCNTL_CKPT_DONE 37
|
||||
#define SQLITE_FCNTL_RESERVE_BYTES 38
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -3535,8 +3533,19 @@ int sqlite3_open_v2(
|
||||
** that check if a database file was a URI that contained a specific query
|
||||
** parameter, and if so obtains the value of that query parameter.
|
||||
**
|
||||
** If F is the database filename pointer passed into the xOpen() method of
|
||||
** a VFS implementation or it is the return value of [sqlite3_db_filename()]
|
||||
** The first parameter to these interfaces (hereafter referred to
|
||||
** as F) must be one of:
|
||||
** <ul>
|
||||
** <li> A database filename pointer created by the SQLite core and
|
||||
** passed into the xOpen() method of a VFS implemention, or
|
||||
** <li> A filename obtained from [sqlite3_db_filename()], or
|
||||
** <li> A new filename constructed using [sqlite3_create_filename()].
|
||||
** </ul>
|
||||
** If the F parameter is not one of the above, then the behavior is
|
||||
** undefined and probably undesirable. Older versions of SQLite were
|
||||
** more tolerant of invalid F parameters than newer versions.
|
||||
**
|
||||
** If F is a suitable filename (as described in the previous paragraph)
|
||||
** and if P is the name of the query parameter, then
|
||||
** sqlite3_uri_parameter(F,P) returns the value of the P
|
||||
** parameter if it exists or a NULL pointer if P does not appear as a
|
||||
@@ -3619,6 +3628,25 @@ const char *sqlite3_filename_database(const char*);
|
||||
const char *sqlite3_filename_journal(const char*);
|
||||
const char *sqlite3_filename_wal(const char*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database File Corresponding To A Journal
|
||||
**
|
||||
** ^If X is the name of a rollback or WAL-mode journal file that is
|
||||
** passed into the xOpen method of [sqlite3_vfs], then
|
||||
** sqlite3_database_file_object(X) returns a pointer to the [sqlite3_file]
|
||||
** object that represents the main database file.
|
||||
**
|
||||
** This routine is intended for use in custom [VFS] implementations
|
||||
** only. It is not a general-purpose interface.
|
||||
** The argument sqlite3_file_object(X) must be a filename pointer that
|
||||
** has been passed into [sqlite3_vfs].xOpen method where the
|
||||
** flags parameter to xOpen contains one of the bits
|
||||
** [SQLITE_OPEN_MAIN_JOURNAL] or [SQLITE_OPEN_WAL]. Any other use
|
||||
** of this routine results in undefined and probably undesirable
|
||||
** behavior.
|
||||
*/
|
||||
sqlite3_file *sqlite3_database_file_object(const char*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Create and Destroy VFS Filenames
|
||||
**
|
||||
@@ -3653,7 +3681,7 @@ const char *sqlite3_filename_wal(const char*);
|
||||
**
|
||||
** The sqlite3_free_filename(Y) routine releases a memory allocation
|
||||
** previously obtained from sqlite3_create_filename(). Invoking
|
||||
** sqlite3_free_filename(Y) is a NULL pointer is a harmless no-op.
|
||||
** sqlite3_free_filename(Y) where Y is a NULL pointer is a harmless no-op.
|
||||
**
|
||||
** If the Y parameter to sqlite3_free_filename(Y) is anything other
|
||||
** than a NULL pointer or a pointer previously acquired from
|
||||
@@ -4260,6 +4288,24 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** ^If the third parameter to sqlite3_bind_text() or sqlite3_bind_text16()
|
||||
** or sqlite3_bind_blob() is a NULL pointer then the fourth parameter
|
||||
** is ignored and the end result is the same as sqlite3_bind_null().
|
||||
** ^If the third parameter to sqlite3_bind_text() is not NULL, then
|
||||
** it should be a pointer to well-formed UTF8 text.
|
||||
** ^If the third parameter to sqlite3_bind_text16() is not NULL, then
|
||||
** it should be a pointer to well-formed UTF16 text.
|
||||
** ^If the third parameter to sqlite3_bind_text64() is not NULL, then
|
||||
** it should be a pointer to a well-formed unicode string that is
|
||||
** either UTF8 if the sixth parameter is SQLITE_UTF8, or UTF16
|
||||
** otherwise.
|
||||
**
|
||||
** [[byte-order determination rules]] ^The byte-order of
|
||||
** UTF16 input text is determined by the byte-order mark (BOM, U+FEFF)
|
||||
** found in first character, which is removed, or in the absence of a BOM
|
||||
** the byte order is the native byte order of the host
|
||||
** machine for sqlite3_bind_text16() or the byte order specified in
|
||||
** the 6th parameter for sqlite3_bind_text64().)^
|
||||
** ^If UTF16 input text contains invalid unicode
|
||||
** characters, then SQLite might change those invalid characters
|
||||
** into the unicode replacement character: U+FFFD.
|
||||
**
|
||||
** ^(In those routines that have a fourth argument, its value is the
|
||||
** number of bytes in the parameter. To be clear: the value is the
|
||||
@@ -4273,7 +4319,7 @@ typedef struct sqlite3_context sqlite3_context;
|
||||
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
||||
** that parameter must be the byte offset
|
||||
** where the NUL terminator would occur assuming the string were NUL
|
||||
** terminated. If any NUL characters occur at byte offsets less than
|
||||
** terminated. If any NUL characters occurs at byte offsets less than
|
||||
** the value of the fourth parameter then the resulting string value will
|
||||
** contain embedded NULs. The result of expressions involving strings
|
||||
** with embedded NULs is undefined.
|
||||
@@ -5598,8 +5644,9 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
|
||||
** as the text of an error message. ^SQLite interprets the error
|
||||
** message string from sqlite3_result_error() as UTF-8. ^SQLite
|
||||
** interprets the string from sqlite3_result_error16() as UTF-16 in native
|
||||
** byte order. ^If the third parameter to sqlite3_result_error()
|
||||
** interprets the string from sqlite3_result_error16() as UTF-16 using
|
||||
** the same [byte-order determination rules] as [sqlite3_bind_text16()].
|
||||
** ^If the third parameter to sqlite3_result_error()
|
||||
** or sqlite3_result_error16() is negative then SQLite takes as the error
|
||||
** message all text up through the first zero character.
|
||||
** ^If the third parameter to sqlite3_result_error() or
|
||||
@@ -5667,6 +5714,25 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** then SQLite makes a copy of the result into space obtained
|
||||
** from [sqlite3_malloc()] before it returns.
|
||||
**
|
||||
** ^For the sqlite3_result_text16(), sqlite3_result_text16le(), and
|
||||
** sqlite3_result_text16be() routines, and for sqlite3_result_text64()
|
||||
** when the encoding is not UTF8, if the input UTF16 begins with a
|
||||
** byte-order mark (BOM, U+FEFF) then the BOM is removed from the
|
||||
** string and the rest of the string is interpreted according to the
|
||||
** byte-order specified by the BOM. ^The byte-order specified by
|
||||
** the BOM at the beginning of the text overrides the byte-order
|
||||
** specified by the interface procedure. ^So, for example, if
|
||||
** sqlite3_result_text16le() is invoked with text that begins
|
||||
** with bytes 0xfe, 0xff (a big-endian byte-order mark) then the
|
||||
** first two bytes of input are skipped and the remaining input
|
||||
** is interpreted as UTF16BE text.
|
||||
**
|
||||
** ^For UTF16 input text to the sqlite3_result_text16(),
|
||||
** sqlite3_result_text16be(), sqlite3_result_text16le(), and
|
||||
** sqlite3_result_text64() routines, if the text contains invalid
|
||||
** UTF16 characters, the invalid characters might be converted
|
||||
** into the unicode replacement character, U+FFFD.
|
||||
**
|
||||
** ^The sqlite3_result_value() interface sets the result of
|
||||
** the application-defined function to be a copy of the
|
||||
** [unprotected sqlite3_value] object specified by the 2nd parameter. ^The
|
||||
@@ -7614,7 +7680,7 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_PENDING_BYTE 11
|
||||
#define SQLITE_TESTCTRL_ASSERT 12
|
||||
#define SQLITE_TESTCTRL_ALWAYS 13
|
||||
#define SQLITE_TESTCTRL_RESERVE 14
|
||||
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
|
||||
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
|
||||
|
||||
@@ -334,6 +334,7 @@ struct sqlite3_api_routines {
|
||||
char *(*create_filename)(const char*,const char*,const char*,
|
||||
int,const char**);
|
||||
void (*free_filename)(char*);
|
||||
sqlite3_file *(*database_file_object)(const char*);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -637,6 +638,7 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
/* Version 3.32.0 and later */
|
||||
#define sqlite3_create_filename sqlite3_api->create_filename
|
||||
#define sqlite3_free_filename sqlite3_api->free_filename
|
||||
#define sqlite3_database_file_object sqlite3_api->database_file_object
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
+1
-1
@@ -233,7 +233,7 @@ SQLITE_NOINLINE int sqlite3RunVacuum(
|
||||
}
|
||||
db->mDbFlags |= DBFLAG_VacuumInto;
|
||||
}
|
||||
nRes = sqlite3BtreeGetOptimalReserve(pMain);
|
||||
nRes = sqlite3BtreeGetRequestedReserve(pMain);
|
||||
|
||||
sqlite3BtreeSetCacheSize(pTemp, db->aDb[iDb].pSchema->cache_size);
|
||||
sqlite3BtreeSetSpillSize(pTemp, sqlite3BtreeSetSpillSize(pMain,0));
|
||||
|
||||
@@ -290,6 +290,9 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
|
||||
int sqlite3VdbeHasSubProgram(Vdbe*);
|
||||
|
||||
int sqlite3NotPureFunc(sqlite3_context*);
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
int sqlite3VdbeBytecodeVtabInit(sqlite3*);
|
||||
#endif
|
||||
|
||||
/* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
|
||||
** each VDBE opcode.
|
||||
|
||||
+11
-3
@@ -31,7 +31,8 @@
|
||||
** "explain" P4 display logic is enabled.
|
||||
*/
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
|
||||
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
|
||||
|| defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) \
|
||||
|| defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
||||
# define VDBE_DISPLAY_P4 1
|
||||
#else
|
||||
# define VDBE_DISPLAY_P4 0
|
||||
@@ -496,7 +497,14 @@ int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(sqlite3*,VdbeCursor*,UnpackedRecord*,int*);
|
||||
int sqlite3VdbeIdxRowid(sqlite3*, BtCursor*, i64*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
||||
int sqlite3VdbeNextOpcode(Vdbe*,Mem*,int,int*,int*,Op**);
|
||||
char *sqlite3VdbeDisplayP4(sqlite3*,Op*);
|
||||
#endif
|
||||
#if defined(SQLITE_ENABLE_EXPLAIN_COMMENTS)
|
||||
char *sqlite3VdbeDisplayComment(sqlite3*,const Op*,const char*);
|
||||
#endif
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN)
|
||||
int sqlite3VdbeList(Vdbe*);
|
||||
#endif
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
@@ -538,7 +546,7 @@ int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
int sqlite3VdbeMemAggValue(Mem*, Mem*, FuncDef*);
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
#if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_BYTECODE_VTAB)
|
||||
const char *sqlite3OpcodeName(int);
|
||||
#endif
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
|
||||
+183
-169
@@ -1464,11 +1464,10 @@ static int translateP(char c, const Op *pOp){
|
||||
** "PX@PY+1" -> "r[X..X+Y]" or "r[x]" if y is 0
|
||||
** "PY..PY" -> "r[X..Y]" or "r[x]" if y<=x
|
||||
*/
|
||||
static int displayComment(
|
||||
char *sqlite3VdbeDisplayComment(
|
||||
sqlite3 *db, /* Optional - Oom error reporting only */
|
||||
const Op *pOp, /* The opcode to be commented */
|
||||
const char *zP4, /* Previously obtained value for P4 */
|
||||
char *zTemp, /* Write result here */
|
||||
int nTemp /* Space available in zTemp[] */
|
||||
const char *zP4 /* Previously obtained value for P4 */
|
||||
){
|
||||
const char *zOpName;
|
||||
const char *zSynopsis;
|
||||
@@ -1476,8 +1475,8 @@ static int displayComment(
|
||||
int ii;
|
||||
char zAlt[50];
|
||||
StrAccum x;
|
||||
sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
|
||||
|
||||
sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
|
||||
zOpName = sqlite3OpcodeName(pOp->opcode);
|
||||
nOpName = sqlite3Strlen30(zOpName);
|
||||
if( zOpName[nOpName+1] ){
|
||||
@@ -1544,10 +1543,12 @@ static int displayComment(
|
||||
}else if( pOp->zComment ){
|
||||
sqlite3_str_appendall(&x, pOp->zComment);
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
return x.nChar;
|
||||
if( (x.accError & SQLITE_NOMEM)!=0 && db!=0 ){
|
||||
sqlite3OomFault(db);
|
||||
}
|
||||
return sqlite3StrAccumFinish(&x);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
#endif /* SQLITE_ENABLE_EXPLAIN_COMMENTS */
|
||||
|
||||
#if VDBE_DISPLAY_P4 && defined(SQLITE_ENABLE_CURSOR_HINTS)
|
||||
/*
|
||||
@@ -1628,11 +1629,11 @@ static void displayP4Expr(StrAccum *p, Expr *pExpr){
|
||||
** Compute a string that describes the P4 parameter for an opcode.
|
||||
** Use zTemp for any required temporary buffer space.
|
||||
*/
|
||||
static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
char *zP4 = zTemp;
|
||||
char *sqlite3VdbeDisplayP4(sqlite3 *db, Op *pOp){
|
||||
char *zP4 = 0;
|
||||
StrAccum x;
|
||||
assert( nTemp>=20 );
|
||||
sqlite3StrAccumInit(&x, 0, zTemp, nTemp, 0);
|
||||
|
||||
sqlite3StrAccumInit(&x, 0, 0, 0, SQLITE_MAX_LENGTH);
|
||||
switch( pOp->p4type ){
|
||||
case P4_KEYINFO: {
|
||||
int j;
|
||||
@@ -1716,36 +1717,32 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
int n = ai[0]; /* The first element of an INTARRAY is always the
|
||||
** count of the number of elements to follow */
|
||||
for(i=1; i<=n; i++){
|
||||
sqlite3_str_appendf(&x, ",%d", ai[i]);
|
||||
sqlite3_str_appendf(&x, "%c%d", (i==1 ? '[' : ','), ai[i]);
|
||||
}
|
||||
zTemp[0] = '[';
|
||||
sqlite3_str_append(&x, "]", 1);
|
||||
break;
|
||||
}
|
||||
case P4_SUBPROGRAM: {
|
||||
sqlite3_str_appendf(&x, "program");
|
||||
zP4 = "program";
|
||||
break;
|
||||
}
|
||||
case P4_DYNBLOB:
|
||||
case P4_ADVANCE: {
|
||||
zTemp[0] = 0;
|
||||
break;
|
||||
}
|
||||
case P4_TABLE: {
|
||||
sqlite3_str_appendf(&x, "%s", pOp->p4.pTab->zName);
|
||||
zP4 = pOp->p4.pTab->zName;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
zP4 = pOp->p4.z;
|
||||
if( zP4==0 ){
|
||||
zP4 = zTemp;
|
||||
zTemp[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3StrAccumFinish(&x);
|
||||
assert( zP4!=0 );
|
||||
return zP4;
|
||||
if( zP4 ) sqlite3_str_appendall(&x, zP4);
|
||||
if( (x.accError & SQLITE_NOMEM)!=0 ){
|
||||
sqlite3OomFault(db);
|
||||
}
|
||||
return sqlite3StrAccumFinish(&x);
|
||||
}
|
||||
#endif /* VDBE_DISPLAY_P4 */
|
||||
|
||||
@@ -1835,24 +1832,28 @@ void sqlite3VdbeLeave(Vdbe *p){
|
||||
*/
|
||||
void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
|
||||
char *zP4;
|
||||
char zPtr[50];
|
||||
char zCom[100];
|
||||
char *zCom;
|
||||
sqlite3 dummyDb;
|
||||
static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
|
||||
if( pOut==0 ) pOut = stdout;
|
||||
zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
|
||||
dummyDb.mallocFailed = 1;
|
||||
zP4 = sqlite3VdbeDisplayP4(&dummyDb, pOp);
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
displayComment(pOp, zP4, zCom, sizeof(zCom));
|
||||
zCom = sqlite3VdbeDisplayComment(0, pOp, zP4);
|
||||
#else
|
||||
zCom[0] = 0;
|
||||
zCom = 0;
|
||||
#endif
|
||||
/* NB: The sqlite3OpcodeName() function is implemented by code created
|
||||
** by the mkopcodeh.awk and mkopcodec.awk scripts which extract the
|
||||
** information from the vdbe.c source text */
|
||||
fprintf(pOut, zFormat1, pc,
|
||||
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5,
|
||||
zCom
|
||||
sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3,
|
||||
zP4 ? zP4 : "", pOp->p5,
|
||||
zCom ? zCom : ""
|
||||
);
|
||||
fflush(pOut);
|
||||
sqlite3_free(zP4);
|
||||
sqlite3_free(zCom);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1943,6 +1944,121 @@ void sqlite3VdbeFrameMemDel(void *pArg){
|
||||
pFrame->v->pDelFrame = pFrame;
|
||||
}
|
||||
|
||||
#if defined(SQLITE_ENABLE_BYTECODE_VTAB) || !defined(SQLITE_OMIT_EXPLAIN)
|
||||
/*
|
||||
** Locate the next opcode to be displayed in EXPLAIN or EXPLAIN
|
||||
** QUERY PLAN output.
|
||||
**
|
||||
** Return SQLITE_ROW on success. Return SQLITE_DONE if there are no
|
||||
** more opcodes to be displayed.
|
||||
*/
|
||||
int sqlite3VdbeNextOpcode(
|
||||
Vdbe *p, /* The statement being explained */
|
||||
Mem *pSub, /* Storage for keeping track of subprogram nesting */
|
||||
int eMode, /* 0: normal. 1: EQP. 2: TablesUsed */
|
||||
int *piPc, /* IN/OUT: Current rowid. Overwritten with next rowid */
|
||||
int *piAddr, /* OUT: Write index into (*paOp)[] here */
|
||||
Op **paOp /* OUT: Write the opcode array here */
|
||||
){
|
||||
int nRow; /* Stop when row count reaches this */
|
||||
int nSub = 0; /* Number of sub-vdbes seen so far */
|
||||
SubProgram **apSub = 0; /* Array of sub-vdbes */
|
||||
int i; /* Next instruction address */
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
Op *aOp = 0; /* Opcode array */
|
||||
int iPc; /* Rowid. Copy of value in *piPc */
|
||||
|
||||
/* When the number of output rows reaches nRow, that means the
|
||||
** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
||||
** nRow is the sum of the number of rows in the main program, plus
|
||||
** the sum of the number of rows in all trigger subprograms encountered
|
||||
** so far. The nRow value will increase as new trigger subprograms are
|
||||
** encountered, but p->pc will eventually catch up to nRow.
|
||||
*/
|
||||
nRow = p->nOp;
|
||||
if( pSub!=0 ){
|
||||
if( pSub->flags&MEM_Blob ){
|
||||
/* pSub is initiallly NULL. It is initialized to a BLOB by
|
||||
** the P4_SUBPROGRAM processing logic below */
|
||||
nSub = pSub->n/sizeof(Vdbe*);
|
||||
apSub = (SubProgram **)pSub->z;
|
||||
}
|
||||
for(i=0; i<nSub; i++){
|
||||
nRow += apSub[i]->nOp;
|
||||
}
|
||||
}
|
||||
iPc = *piPc;
|
||||
while(1){ /* Loop exits via break */
|
||||
i = iPc++;
|
||||
if( i>=nRow ){
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_DONE;
|
||||
break;
|
||||
}
|
||||
if( i<p->nOp ){
|
||||
/* The rowid is small enough that we are still in the
|
||||
** main program. */
|
||||
aOp = p->aOp;
|
||||
}else{
|
||||
/* We are currently listing subprograms. Figure out which one and
|
||||
** pick up the appropriate opcode. */
|
||||
int j;
|
||||
i -= p->nOp;
|
||||
assert( apSub!=0 );
|
||||
assert( nSub>0 );
|
||||
for(j=0; i>=apSub[j]->nOp; j++){
|
||||
i -= apSub[j]->nOp;
|
||||
assert( i<apSub[j]->nOp || j+1<nSub );
|
||||
}
|
||||
aOp = apSub[j]->aOp;
|
||||
}
|
||||
|
||||
/* When an OP_Program opcode is encounter (the only opcode that has
|
||||
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
||||
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
||||
** has not already been seen.
|
||||
*/
|
||||
if( pSub!=0 && aOp[i].p4type==P4_SUBPROGRAM ){
|
||||
int nByte = (nSub+1)*sizeof(SubProgram*);
|
||||
int j;
|
||||
for(j=0; j<nSub; j++){
|
||||
if( apSub[j]==aOp[i].p4.pProgram ) break;
|
||||
}
|
||||
if( j==nSub ){
|
||||
p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
apSub = (SubProgram **)pSub->z;
|
||||
apSub[nSub++] = aOp[i].p4.pProgram;
|
||||
MemSetTypeFlag(pSub, MEM_Blob);
|
||||
pSub->n = nSub*sizeof(SubProgram*);
|
||||
nRow += aOp[i].p4.pProgram->nOp;
|
||||
}
|
||||
}
|
||||
if( eMode==0 ) break;
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
if( eMode==2 ){
|
||||
Op *pOp = aOp + i;
|
||||
if( pOp->opcode==OP_OpenRead ) break;
|
||||
if( pOp->opcode==OP_OpenWrite && (pOp->p5 & OPFLAG_P2ISREG)==0 ) break;
|
||||
if( pOp->opcode==OP_ReopenIdx ) break;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
assert( eMode==1 );
|
||||
if( aOp[i].opcode==OP_Explain ) break;
|
||||
if( aOp[i].opcode==OP_Init && iPc>1 ) break;
|
||||
}
|
||||
}
|
||||
*piPc = iPc;
|
||||
*piAddr = i;
|
||||
*paOp = aOp;
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_BYTECODE_VTAB || !SQLITE_OMIT_EXPLAIN */
|
||||
|
||||
|
||||
/*
|
||||
** Delete a VdbeFrame object and its contents. VdbeFrame objects are
|
||||
@@ -1983,16 +2099,14 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){
|
||||
int sqlite3VdbeList(
|
||||
Vdbe *p /* The VDBE */
|
||||
){
|
||||
int nRow; /* Stop when row count reaches this */
|
||||
int nSub = 0; /* Number of sub-vdbes seen so far */
|
||||
SubProgram **apSub = 0; /* Array of sub-vdbes */
|
||||
Mem *pSub = 0; /* Memory cell hold array of subprogs */
|
||||
sqlite3 *db = p->db; /* The database connection */
|
||||
int i; /* Loop counter */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Mem *pMem = &p->aMem[1]; /* First Mem of result set */
|
||||
int bListSubprogs = (p->explain==1 || (db->flags & SQLITE_TriggerEQP)!=0);
|
||||
Op *pOp = 0;
|
||||
Op *aOp; /* Array of opcodes */
|
||||
Op *pOp; /* Current opcode */
|
||||
|
||||
assert( p->explain );
|
||||
assert( p->magic==VDBE_MAGIC_RUN );
|
||||
@@ -2012,14 +2126,6 @@ int sqlite3VdbeList(
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
|
||||
/* When the number of output rows reaches nRow, that means the
|
||||
** listing has finished and sqlite3_step() should return SQLITE_DONE.
|
||||
** nRow is the sum of the number of rows in the main program, plus
|
||||
** the sum of the number of rows in all trigger subprograms encountered
|
||||
** so far. The nRow value will increase as new trigger subprograms are
|
||||
** encountered, but p->pc will eventually catch up to nRow.
|
||||
*/
|
||||
nRow = p->nOp;
|
||||
if( bListSubprogs ){
|
||||
/* The first 8 memory cells are used for the result set. So we will
|
||||
** commandeer the 9th cell to use as storage for an array of pointers
|
||||
@@ -2027,147 +2133,55 @@ int sqlite3VdbeList(
|
||||
** cells. */
|
||||
assert( p->nMem>9 );
|
||||
pSub = &p->aMem[9];
|
||||
if( pSub->flags&MEM_Blob ){
|
||||
/* On the first call to sqlite3_step(), pSub will hold a NULL. It is
|
||||
** initialized to a BLOB by the P4_SUBPROGRAM processing logic below */
|
||||
nSub = pSub->n/sizeof(Vdbe*);
|
||||
apSub = (SubProgram **)pSub->z;
|
||||
}
|
||||
for(i=0; i<nSub; i++){
|
||||
nRow += apSub[i]->nOp;
|
||||
}
|
||||
}else{
|
||||
pSub = 0;
|
||||
}
|
||||
|
||||
while(1){ /* Loop exits via break */
|
||||
i = p->pc++;
|
||||
if( i>=nRow ){
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_DONE;
|
||||
break;
|
||||
}
|
||||
if( i<p->nOp ){
|
||||
/* The output line number is small enough that we are still in the
|
||||
** main program. */
|
||||
pOp = &p->aOp[i];
|
||||
}else{
|
||||
/* We are currently listing subprograms. Figure out which one and
|
||||
** pick up the appropriate opcode. */
|
||||
int j;
|
||||
i -= p->nOp;
|
||||
assert( apSub!=0 );
|
||||
assert( nSub>0 );
|
||||
for(j=0; i>=apSub[j]->nOp; j++){
|
||||
i -= apSub[j]->nOp;
|
||||
assert( i<apSub[j]->nOp || j+1<nSub );
|
||||
}
|
||||
pOp = &apSub[j]->aOp[i];
|
||||
}
|
||||
|
||||
/* When an OP_Program opcode is encounter (the only opcode that has
|
||||
** a P4_SUBPROGRAM argument), expand the size of the array of subprograms
|
||||
** kept in p->aMem[9].z to hold the new program - assuming this subprogram
|
||||
** has not already been seen.
|
||||
*/
|
||||
if( bListSubprogs && pOp->p4type==P4_SUBPROGRAM ){
|
||||
int nByte = (nSub+1)*sizeof(SubProgram*);
|
||||
int j;
|
||||
for(j=0; j<nSub; j++){
|
||||
if( apSub[j]==pOp->p4.pProgram ) break;
|
||||
}
|
||||
if( j==nSub ){
|
||||
p->rc = sqlite3VdbeMemGrow(pSub, nByte, nSub!=0);
|
||||
if( p->rc!=SQLITE_OK ){
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
}
|
||||
apSub = (SubProgram **)pSub->z;
|
||||
apSub[nSub++] = pOp->p4.pProgram;
|
||||
pSub->flags |= MEM_Blob;
|
||||
pSub->n = nSub*sizeof(SubProgram*);
|
||||
nRow += pOp->p4.pProgram->nOp;
|
||||
}
|
||||
}
|
||||
if( p->explain<2 ) break;
|
||||
if( pOp->opcode==OP_Explain ) break;
|
||||
if( pOp->opcode==OP_Init && p->pc>1 ) break;
|
||||
}
|
||||
/* Figure out which opcode is next to display */
|
||||
rc = sqlite3VdbeNextOpcode(p, pSub, p->explain==2, &p->pc, &i, &aOp);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
pOp = aOp + i;
|
||||
if( AtomicLoad(&db->u1.isInterrupted) ){
|
||||
p->rc = SQLITE_INTERRUPT;
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3VdbeError(p, sqlite3ErrStr(p->rc));
|
||||
}else{
|
||||
char *zP4;
|
||||
if( p->explain==1 ){
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = i; /* Program counter */
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
|
||||
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
}
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p1; /* P1 */
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p2; /* P2 */
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 100) ){ /* P4 */
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
zP4 = displayP4(pOp, pMem->z, pMem->szMalloc);
|
||||
if( zP4!=pMem->z ){
|
||||
pMem->n = 0;
|
||||
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
|
||||
char *zP4 = sqlite3VdbeDisplayP4(db, pOp);
|
||||
if( p->explain==2 ){
|
||||
sqlite3VdbeMemSetInt64(pMem, pOp->p1);
|
||||
sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
|
||||
sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
|
||||
sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
|
||||
p->nResColumn = 4;
|
||||
}else{
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
}
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 4) ){
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
pMem->n = 2;
|
||||
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
sqlite3VdbeMemSetInt64(pMem+0, i);
|
||||
sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
|
||||
-1, SQLITE_UTF8, SQLITE_STATIC);
|
||||
sqlite3VdbeMemSetInt64(pMem+2, pOp->p1);
|
||||
sqlite3VdbeMemSetInt64(pMem+3, pOp->p2);
|
||||
sqlite3VdbeMemSetInt64(pMem+4, pOp->p3);
|
||||
/* pMem+5 for p4 is done last */
|
||||
sqlite3VdbeMemSetInt64(pMem+6, pOp->p5);
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
if( sqlite3VdbeMemClearAndResize(pMem, 500) ){
|
||||
assert( p->db->mallocFailed );
|
||||
return SQLITE_ERROR;
|
||||
{
|
||||
char *zCom = sqlite3VdbeDisplayComment(db, pOp, zP4);
|
||||
sqlite3VdbeMemSetStr(pMem+7, zCom, -1, SQLITE_UTF8, sqlite3_free);
|
||||
}
|
||||
pMem->flags = MEM_Str|MEM_Term;
|
||||
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
#else
|
||||
pMem->flags = MEM_Null; /* Comment */
|
||||
sqlite3VdbeMemSetNull(pMem+7);
|
||||
#endif
|
||||
sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
|
||||
p->nResColumn = 8;
|
||||
}
|
||||
p->pResultSet = pMem;
|
||||
if( db->mallocFailed ){
|
||||
p->rc = SQLITE_NOMEM;
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_ROW;
|
||||
}
|
||||
|
||||
p->nResColumn = 8 - 4*(p->explain-1);
|
||||
p->pResultSet = &p->aMem[1];
|
||||
p->rc = SQLITE_OK;
|
||||
rc = SQLITE_ROW;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
** 2020-03-23
|
||||
**
|
||||
** The author disclaims copyright to this source code. In place of
|
||||
** a legal notice, here is a blessing:
|
||||
**
|
||||
** May you do good and not evil.
|
||||
** May you find forgiveness for yourself and forgive others.
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
** This file implements virtual-tables for examining the bytecode content
|
||||
** of a prepared statement.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
|
||||
/* An instance of the bytecode() table-valued function.
|
||||
*/
|
||||
typedef struct bytecodevtab bytecodevtab;
|
||||
struct bytecodevtab {
|
||||
sqlite3_vtab base; /* Base class - must be first */
|
||||
sqlite3 *db; /* Database connection */
|
||||
int bTablesUsed; /* 2 for tables_used(). 0 for bytecode(). */
|
||||
};
|
||||
|
||||
/* A cursor for scanning through the bytecode
|
||||
*/
|
||||
typedef struct bytecodevtab_cursor bytecodevtab_cursor;
|
||||
struct bytecodevtab_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
sqlite3_stmt *pStmt; /* The statement whose bytecode is displayed */
|
||||
int iRowid; /* The rowid of the output table */
|
||||
int iAddr; /* Address */
|
||||
int needFinalize; /* Cursors owns pStmt and must finalize it */
|
||||
int showSubprograms; /* Provide a listing of subprograms */
|
||||
Op *aOp; /* Operand array */
|
||||
char *zP4; /* Rendered P4 value */
|
||||
const char *zType; /* tables_used.type */
|
||||
const char *zSchema; /* tables_used.schema */
|
||||
const char *zName; /* tables_used.name */
|
||||
Mem sub; /* Subprograms */
|
||||
};
|
||||
|
||||
/*
|
||||
** Create a new bytecode() table-valued function.
|
||||
*/
|
||||
static int bytecodevtabConnect(
|
||||
sqlite3 *db,
|
||||
void *pAux,
|
||||
int argc, const char *const*argv,
|
||||
sqlite3_vtab **ppVtab,
|
||||
char **pzErr
|
||||
){
|
||||
bytecodevtab *pNew;
|
||||
int rc;
|
||||
int isTabUsed = pAux!=0;
|
||||
const char *azSchema[2] = {
|
||||
/* bytecode() schema */
|
||||
"CREATE TABLE x("
|
||||
"addr INT,"
|
||||
"opcode TEXT,"
|
||||
"p1 INT,"
|
||||
"p2 INT,"
|
||||
"p3 INT,"
|
||||
"p4 TEXT,"
|
||||
"p5 INT,"
|
||||
"comment TEXT,"
|
||||
"subprog TEXT,"
|
||||
"stmt HIDDEN"
|
||||
");",
|
||||
|
||||
/* Tables_used() schema */
|
||||
"CREATE TABLE x("
|
||||
"type TEXT,"
|
||||
"schema TEXT,"
|
||||
"name TEXT,"
|
||||
"wr INT,"
|
||||
"subprog TEXT,"
|
||||
"stmt HIDDEN"
|
||||
");"
|
||||
};
|
||||
|
||||
rc = sqlite3_declare_vtab(db, azSchema[isTabUsed]);
|
||||
if( rc==SQLITE_OK ){
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) );
|
||||
*ppVtab = (sqlite3_vtab*)pNew;
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->db = db;
|
||||
pNew->bTablesUsed = isTabUsed*2;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This method is the destructor for bytecodevtab objects.
|
||||
*/
|
||||
static int bytecodevtabDisconnect(sqlite3_vtab *pVtab){
|
||||
bytecodevtab *p = (bytecodevtab*)pVtab;
|
||||
sqlite3_free(p);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Constructor for a new bytecodevtab_cursor object.
|
||||
*/
|
||||
static int bytecodevtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
|
||||
bytecodevtab *pVTab = (bytecodevtab*)p;
|
||||
bytecodevtab_cursor *pCur;
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
sqlite3VdbeMemInit(&pCur->sub, pVTab->db, 1);
|
||||
*ppCursor = &pCur->base;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Clear all internal content from a bytecodevtab cursor.
|
||||
*/
|
||||
static void bytecodevtabCursorClear(bytecodevtab_cursor *pCur){
|
||||
sqlite3_free(pCur->zP4);
|
||||
pCur->zP4 = 0;
|
||||
sqlite3VdbeMemRelease(&pCur->sub);
|
||||
sqlite3VdbeMemSetNull(&pCur->sub);
|
||||
if( pCur->needFinalize ){
|
||||
sqlite3_finalize(pCur->pStmt);
|
||||
}
|
||||
pCur->pStmt = 0;
|
||||
pCur->needFinalize = 0;
|
||||
pCur->zType = 0;
|
||||
pCur->zSchema = 0;
|
||||
pCur->zName = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Destructor for a bytecodevtab_cursor.
|
||||
*/
|
||||
static int bytecodevtabClose(sqlite3_vtab_cursor *cur){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
||||
bytecodevtabCursorClear(pCur);
|
||||
sqlite3_free(pCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a bytecodevtab_cursor to its next row of output.
|
||||
*/
|
||||
static int bytecodevtabNext(sqlite3_vtab_cursor *cur){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
||||
bytecodevtab *pTab = (bytecodevtab*)cur->pVtab;
|
||||
int rc;
|
||||
if( pCur->zP4 ){
|
||||
sqlite3_free(pCur->zP4);
|
||||
pCur->zP4 = 0;
|
||||
}
|
||||
if( pCur->zName ){
|
||||
pCur->zName = 0;
|
||||
pCur->zType = 0;
|
||||
pCur->zSchema = 0;
|
||||
}
|
||||
rc = sqlite3VdbeNextOpcode(
|
||||
(Vdbe*)pCur->pStmt,
|
||||
pCur->showSubprograms ? &pCur->sub : 0,
|
||||
pTab->bTablesUsed,
|
||||
&pCur->iRowid,
|
||||
&pCur->iAddr,
|
||||
&pCur->aOp);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3VdbeMemSetNull(&pCur->sub);
|
||||
pCur->aOp = 0;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if the cursor has been moved off of the last
|
||||
** row of output.
|
||||
*/
|
||||
static int bytecodevtabEof(sqlite3_vtab_cursor *cur){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
||||
return pCur->aOp==0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return values of columns for the row at which the bytecodevtab_cursor
|
||||
** is currently pointing.
|
||||
*/
|
||||
static int bytecodevtabColumn(
|
||||
sqlite3_vtab_cursor *cur, /* The cursor */
|
||||
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
|
||||
int i /* Which column to return */
|
||||
){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
||||
bytecodevtab *pVTab = (bytecodevtab*)cur->pVtab;
|
||||
Op *pOp = pCur->aOp + pCur->iAddr;
|
||||
if( pVTab->bTablesUsed ){
|
||||
if( i==4 ){
|
||||
i = 8;
|
||||
}else{
|
||||
if( i<=2 && pCur->zType==0 ){
|
||||
Schema *pSchema;
|
||||
HashElem *k;
|
||||
int iDb = pOp->p3;
|
||||
int iRoot = pOp->p2;
|
||||
sqlite3 *db = pVTab->db;
|
||||
pSchema = db->aDb[iDb].pSchema;
|
||||
pCur->zSchema = db->aDb[iDb].zDbSName;
|
||||
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
Table *pTab = (Table*)sqliteHashData(k);
|
||||
if( !IsVirtual(pTab) && pTab->tnum==iRoot ){
|
||||
pCur->zName = pTab->zName;
|
||||
pCur->zType = "table";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( pCur->zName==0 ){
|
||||
for(k=sqliteHashFirst(&pSchema->idxHash); k; k=sqliteHashNext(k)){
|
||||
Index *pIdx = (Index*)sqliteHashData(k);
|
||||
if( pIdx->tnum==iRoot ){
|
||||
pCur->zName = pIdx->zName;
|
||||
pCur->zType = "index";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 10;
|
||||
}
|
||||
}
|
||||
switch( i ){
|
||||
case 0: /* addr */
|
||||
sqlite3_result_int(ctx, pCur->iAddr);
|
||||
break;
|
||||
case 1: /* opcode */
|
||||
sqlite3_result_text(ctx, (char*)sqlite3OpcodeName(pOp->opcode),
|
||||
-1, SQLITE_STATIC);
|
||||
break;
|
||||
case 2: /* p1 */
|
||||
sqlite3_result_int(ctx, pOp->p1);
|
||||
break;
|
||||
case 3: /* p2 */
|
||||
sqlite3_result_int(ctx, pOp->p2);
|
||||
break;
|
||||
case 4: /* p3 */
|
||||
sqlite3_result_int(ctx, pOp->p3);
|
||||
break;
|
||||
case 5: /* p4 */
|
||||
case 7: /* comment */
|
||||
if( pCur->zP4==0 ){
|
||||
pCur->zP4 = sqlite3VdbeDisplayP4(pVTab->db, pOp);
|
||||
}
|
||||
if( i==5 ){
|
||||
sqlite3_result_text(ctx, pCur->zP4, -1, SQLITE_STATIC);
|
||||
}else{
|
||||
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
|
||||
char *zCom = sqlite3VdbeDisplayComment(pVTab->db, pOp, pCur->zP4);
|
||||
sqlite3_result_text(ctx, zCom, -1, sqlite3_free);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 6: /* p5 */
|
||||
sqlite3_result_int(ctx, pOp->p5);
|
||||
break;
|
||||
case 8: { /* subprog */
|
||||
Op *aOp = pCur->aOp;
|
||||
assert( aOp[0].opcode==OP_Init );
|
||||
assert( aOp[0].p4.z==0 || strncmp(aOp[0].p4.z,"-" "- ",3)==0 );
|
||||
if( pCur->iRowid==pCur->iAddr+1 ){
|
||||
break; /* Result is NULL for the main program */
|
||||
}else if( aOp[0].p4.z!=0 ){
|
||||
sqlite3_result_text(ctx, aOp[0].p4.z+3, -1, SQLITE_STATIC);
|
||||
}else{
|
||||
sqlite3_result_text(ctx, "(FK)", 4, SQLITE_STATIC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: /* tables_used.type */
|
||||
sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 11: /* tables_used.schema */
|
||||
sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 12: /* tables_used.name */
|
||||
sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
|
||||
break;
|
||||
case 13: /* tables_used.wr */
|
||||
sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
|
||||
break;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the rowid for the current row. In this implementation, the
|
||||
** rowid is the same as the output value.
|
||||
*/
|
||||
static int bytecodevtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor*)cur;
|
||||
*pRowid = pCur->iRowid;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a cursor.
|
||||
**
|
||||
** idxNum==0 means show all subprograms
|
||||
** idxNum==1 means show only the main bytecode and omit subprograms.
|
||||
*/
|
||||
static int bytecodevtabFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
bytecodevtab_cursor *pCur = (bytecodevtab_cursor *)pVtabCursor;
|
||||
bytecodevtab *pVTab = (bytecodevtab *)pVtabCursor->pVtab;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
bytecodevtabCursorClear(pCur);
|
||||
pCur->iRowid = 0;
|
||||
pCur->iAddr = 0;
|
||||
pCur->showSubprograms = idxNum==0;
|
||||
assert( argc==1 );
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
|
||||
const char *zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zSql==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
rc = sqlite3_prepare_v2(pVTab->db, zSql, -1, &pCur->pStmt, 0);
|
||||
pCur->needFinalize = 1;
|
||||
}
|
||||
}else{
|
||||
pCur->pStmt = (sqlite3_stmt*)sqlite3_value_pointer(argv[0],"stmt-pointer");
|
||||
}
|
||||
if( pCur->pStmt==0 ){
|
||||
pVTab->base.zErrMsg = sqlite3_mprintf(
|
||||
"argument to %s() is not a valid SQL statement",
|
||||
pVTab->bTablesUsed ? "tables_used" : "bytecode"
|
||||
);
|
||||
rc = SQLITE_ERROR;
|
||||
}else{
|
||||
bytecodevtabNext(pVtabCursor);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** We must have a single stmt=? constraint that will be passed through
|
||||
** into the xFilter method. If there is no valid stmt=? constraint,
|
||||
** then return an SQLITE_CONSTRAINT error.
|
||||
*/
|
||||
static int bytecodevtabBestIndex(
|
||||
sqlite3_vtab *tab,
|
||||
sqlite3_index_info *pIdxInfo
|
||||
){
|
||||
int i;
|
||||
int rc = SQLITE_CONSTRAINT;
|
||||
struct sqlite3_index_constraint *p;
|
||||
bytecodevtab *pVTab = (bytecodevtab*)tab;
|
||||
int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
|
||||
pIdxInfo->estimatedCost = (double)100;
|
||||
pIdxInfo->estimatedRows = 100;
|
||||
pIdxInfo->idxNum = 0;
|
||||
for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
|
||||
if( p->usable==0 ) continue;
|
||||
if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==iBaseCol+1 ){
|
||||
rc = SQLITE_OK;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
}
|
||||
if( p->op==SQLITE_INDEX_CONSTRAINT_ISNULL && p->iColumn==iBaseCol ){
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
pIdxInfo->idxNum = 1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This following structure defines all the methods for the
|
||||
** virtual table.
|
||||
*/
|
||||
static sqlite3_module bytecodevtabModule = {
|
||||
/* iVersion */ 0,
|
||||
/* xCreate */ 0,
|
||||
/* xConnect */ bytecodevtabConnect,
|
||||
/* xBestIndex */ bytecodevtabBestIndex,
|
||||
/* xDisconnect */ bytecodevtabDisconnect,
|
||||
/* xDestroy */ 0,
|
||||
/* xOpen */ bytecodevtabOpen,
|
||||
/* xClose */ bytecodevtabClose,
|
||||
/* xFilter */ bytecodevtabFilter,
|
||||
/* xNext */ bytecodevtabNext,
|
||||
/* xEof */ bytecodevtabEof,
|
||||
/* xColumn */ bytecodevtabColumn,
|
||||
/* xRowid */ bytecodevtabRowid,
|
||||
/* xUpdate */ 0,
|
||||
/* xBegin */ 0,
|
||||
/* xSync */ 0,
|
||||
/* xCommit */ 0,
|
||||
/* xRollback */ 0,
|
||||
/* xFindMethod */ 0,
|
||||
/* xRename */ 0,
|
||||
/* xSavepoint */ 0,
|
||||
/* xRelease */ 0,
|
||||
/* xRollbackTo */ 0,
|
||||
/* xShadowName */ 0
|
||||
};
|
||||
|
||||
|
||||
int sqlite3VdbeBytecodeVtabInit(sqlite3 *db){
|
||||
int rc;
|
||||
rc = sqlite3_create_module(db, "bytecode", &bytecodevtabModule, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_module(db, "tables_used", &bytecodevtabModule, &db);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif /* SQLITE_ENABLE_BYTECODE_VTAB */
|
||||
+2
-2
@@ -51,8 +51,8 @@ proc do_temptables_test {tn sql temptables} {
|
||||
set ret ""
|
||||
db eval "EXPLAIN [set sql]" {
|
||||
if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
|
||||
if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
|
||||
if {$p5 == "08"} {
|
||||
if {$p5!=8 && $p5!=0} { error "p5 = $p5" }
|
||||
if {$p5==8} {
|
||||
lappend ret hash
|
||||
} else {
|
||||
lappend ret btree
|
||||
|
||||
@@ -5834,4 +5834,17 @@ do_catchsql_test 36.1 {
|
||||
INSERT INTO f(f) VALUES ('merge=59,59');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 37.0 {
|
||||
CREATE VIRTUAL TABLE f USING fts3(a,b);
|
||||
INSERT INTO f_segdir VALUES (28,0,0,0,'0 0',x'00');
|
||||
INSERT INTO f_segdir VALUES (0,241,0,0,'0 0',x'0001000030310000f1');
|
||||
}
|
||||
|
||||
do_catchsql_test 37.1 {
|
||||
INSERT INTO f VALUES (0,x'00');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -315,4 +315,12 @@ do_catchsql_test 10.1 {
|
||||
INSERT INTO f(f) VALUES ('merge=69,59');
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 11.0 {
|
||||
CREATE VIRTUAL TABLE xyz USING fts3();
|
||||
}
|
||||
do_execsql_test 11.1 {
|
||||
SELECT * FROM xyz WHERE xyz MATCH 'a NEAR/4294836224 a';
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+2
-2
@@ -234,13 +234,13 @@ if {$tcl_platform(byteOrder)=="littleEndian"} {
|
||||
} else {
|
||||
set res {X'0000000200000000000000000000000E0000000E00000001000000010000000100000001'}
|
||||
}
|
||||
do_execsql_test fts4aa-6.10 {
|
||||
do_catchsql_test fts4aa-6.10 {
|
||||
CREATE VIRTUAL TABLE f USING fts4();
|
||||
INSERT INTO f_segdir VALUES (77,91,0,0,'255 77',x'0001308000004d5c4ddddddd4d4d7b4d4d4d614d8019ff4d05000001204d4d2e4d6e4d4d4d4b4d6c4d004d4d4d4d4d4d3d000000004d5d4d4d645d4d004d4d4d4d4d4d4d4d4d454d6910004d05ffff054d646c4d004d5d4d4d4d4d3d000000004d4d4d4d4d4d4d4d4d4d4d69624d4d4d04004d4d4d4d4d604d4ce1404d554d45');
|
||||
INSERT INTO f_segdir VALUES (77,108,0,0,'255 77',x'0001310000fa64004d4d4d3c5d4d654d4d4d614d8000ff4d05000001204d4d2e4d6e4d4d4dff4d4d4d4d4d4d00104d4d4d4d000000004d4d4d0400311d4d4d4d4d4d4d4d4d4d684d6910004d05ffff054d4d6c4d004d4d4d4d4d4d3d000000004d4d4d4d644d4d4d4d4d4d69624d4d4d03ed4d4d4d4d4d604d4ce1404d550080');
|
||||
INSERT INTO f_stat VALUES (0,x'80808080100000000064004d4d4d3c4d4d654d4d4d614d8000ff4df6ff1a00204d4d2e4d6e4d4d4d104d4d4d4d4d4d00104d4d4d4d4d4d69574d4d4d000031044d4d4d3e4d4d4c4d05004d6910');
|
||||
SELECT quote(matchinfo(f,'pnax')) from f where f match '0 1';
|
||||
} $res
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
# 2019-11-18 Detect infinite loop in fts3SelectLeaf()
|
||||
db close
|
||||
|
||||
@@ -293,5 +293,36 @@ do_execsql_test 8.1 {
|
||||
WHERE (t1.c0 BETWEEN 0 AND 0) > ('' AND t0.c0);
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [45f4bf4eb].
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 9.0 {
|
||||
CREATE TABLE t0(c0 INT);
|
||||
CREATE VIEW v0(c0) AS SELECT CAST(t0.c0 AS INTEGER) FROM t0;
|
||||
INSERT INTO t0(c0) VALUES (0);
|
||||
}
|
||||
|
||||
do_execsql_test 9.1 {
|
||||
SELECT typeof(c0), c0 FROM v0 WHERE c0>='0'
|
||||
} {integer 0}
|
||||
|
||||
do_execsql_test 9.2 {
|
||||
SELECT * FROM t0, v0 WHERE v0.c0 >= '0';
|
||||
} {0 0}
|
||||
|
||||
do_execsql_test 9.3 {
|
||||
SELECT * FROM t0 LEFT JOIN v0 WHERE v0.c0 >= '0';
|
||||
} {0 0}
|
||||
|
||||
do_execsql_test 9.4 {
|
||||
SELECT * FROM t0 LEFT JOIN v0 ON v0.c0 >= '0';
|
||||
} {0 0}
|
||||
|
||||
do_execsql_test 9.5 {
|
||||
SELECT * FROM t0 LEFT JOIN v0 ON v0.c0 >= '0' WHERE TRUE
|
||||
UNION SELECT 0,0 WHERE 0;
|
||||
} {0 0}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
+16
-2
@@ -493,7 +493,14 @@ do_test shell1-3.15.2 {
|
||||
do_test shell1-3.15.3 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".output FOO BAD"
|
||||
} {1 {Usage: .output [-e|-x|FILE]}}
|
||||
} {1 {ERROR: extra parameter: "BAD". Usage:
|
||||
.output ?FILE? Send output to FILE or stdout if FILE is omitted
|
||||
If FILE begins with '|' then open it as a pipe.
|
||||
Options:
|
||||
--bom Prefix output with a UTF8 byte-order mark
|
||||
-e Send output to the system text editor
|
||||
-x Send output as CSV to a spreadsheet
|
||||
child process exited abnormally}}
|
||||
|
||||
# .output stdout Send output to the screen
|
||||
do_test shell1-3.16.1 {
|
||||
@@ -502,7 +509,14 @@ do_test shell1-3.16.1 {
|
||||
do_test shell1-3.16.2 {
|
||||
# too many arguments
|
||||
catchcmd "test.db" ".output stdout BAD"
|
||||
} {1 {Usage: .output [-e|-x|FILE]}}
|
||||
} {1 {ERROR: extra parameter: "BAD". Usage:
|
||||
.output ?FILE? Send output to FILE or stdout if FILE is omitted
|
||||
If FILE begins with '|' then open it as a pipe.
|
||||
Options:
|
||||
--bom Prefix output with a UTF8 byte-order mark
|
||||
-e Send output to the system text editor
|
||||
-x Send output as CSV to a spreadsheet
|
||||
child process exited abnormally}}
|
||||
|
||||
# .prompt MAIN CONTINUE Replace the standard prompts
|
||||
do_test shell1-3.17.1 {
|
||||
|
||||
@@ -157,4 +157,38 @@ do_execsql_test 600 {
|
||||
WHERE x='good' AND y='good';
|
||||
} {good good}
|
||||
|
||||
# 2020-04-24: Another test case for the previous (1dcb4d44964846ad)
|
||||
# ticket. The test case comes from
|
||||
# https://stackoverflow.com/questions/61399253/sqlite3-different-result-in-console-compared-to-python-script/
|
||||
# Output verified against postgresql.
|
||||
#
|
||||
do_execsql_test 610 {
|
||||
CREATE TABLE tableA(
|
||||
ID int,
|
||||
RunYearMonth int
|
||||
);
|
||||
INSERT INTO tableA VALUES(1,202003),(2,202003),(3,202003),(4,202004),
|
||||
(5,202004),(6,202004),(7,202004),(8,202004);
|
||||
CREATE TABLE tableB (
|
||||
ID int,
|
||||
RunYearMonth int
|
||||
);
|
||||
INSERT INTO tableB VALUES(1,202004),(2,202004),(3,202004),(4,202004),
|
||||
(5,202004);
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT *
|
||||
FROM tableA
|
||||
WHERE RunYearMonth = 202004
|
||||
) AS A
|
||||
INNER JOIN (
|
||||
SELECT *
|
||||
FROM tableB
|
||||
WHERE RunYearMonth = 202004
|
||||
) AS B
|
||||
ON A.ID = B.ID
|
||||
AND A.RunYearMonth = B.RunYearMonth;
|
||||
} {4 202004 4 202004 5 202004 5 202004}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -341,6 +341,7 @@ foreach file {
|
||||
vdbe.c
|
||||
vdbeblob.c
|
||||
vdbesort.c
|
||||
vdbevtab.c
|
||||
memjournal.c
|
||||
|
||||
walker.c
|
||||
|
||||
@@ -587,6 +587,9 @@ set free_percent2 [percent $free_pgcnt2 $file_pgcnt]
|
||||
|
||||
set file_pgcnt2 [expr {$inuse_pgcnt+$free_pgcnt2+$av_pgcnt}]
|
||||
|
||||
# Account for the lockbyte page
|
||||
if {$file_pgcnt2*$pageSize>1073742335} {incr file_pgcnt2}
|
||||
|
||||
set ntable [db eval {SELECT count(*)+1 FROM sqlite_master WHERE type='table'}]
|
||||
set nindex [db eval {SELECT count(*) FROM sqlite_master WHERE type='index'}]
|
||||
set sql {SELECT count(*) FROM sqlite_master WHERE name LIKE 'sqlite_autoindex%'}
|
||||
|
||||
Reference in New Issue
Block a user