mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Merge trunk into jni branch.
FossilOrigin-Name: 4f0aeeba0287e846908180eab6f7080ebe1323ebe49340771864d110e1ca5b2b
This commit is contained in:
14
Makefile.msc
14
Makefile.msc
@@ -52,6 +52,13 @@ MINIMAL_AMALGAMATION = 0
|
||||
USE_STDCALL = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use structured exception handling (SEH) for WAL mode
|
||||
# in the core library.
|
||||
#
|
||||
!IFNDEF USE_SEH
|
||||
USE_SEH = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to have the shell executable link against the core dynamic
|
||||
# link library.
|
||||
#
|
||||
@@ -389,6 +396,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# Should structured exception handling (SEH) be enabled for WAL mode in
|
||||
# the core library?
|
||||
#
|
||||
!IF $(USE_SEH)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_USE_SEH=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
|
@@ -52,6 +52,13 @@ MINIMAL_AMALGAMATION = 0
|
||||
USE_STDCALL = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to use structured exception handling (SEH) for WAL mode
|
||||
# in the core library.
|
||||
#
|
||||
!IFNDEF USE_SEH
|
||||
USE_SEH = 0
|
||||
!ENDIF
|
||||
|
||||
# Set this non-0 to have the shell executable link against the core dynamic
|
||||
# link library.
|
||||
#
|
||||
@@ -311,6 +318,13 @@ OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_MATH_FUNCTIONS
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RBU=1
|
||||
!ENDIF
|
||||
|
||||
# Should structured exception handling (SEH) be enabled for WAL mode in
|
||||
# the core library?
|
||||
#
|
||||
!IF $(USE_SEH)!=0
|
||||
OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_USE_SEH=1
|
||||
!ENDIF
|
||||
|
||||
# These are the "extended" SQLite compilation options used when compiling for
|
||||
# the Windows 10 platform.
|
||||
#
|
||||
|
@@ -179,7 +179,6 @@ SQLITE_OPT = \
|
||||
-DSQLITE_OMIT_DEPRECATED \
|
||||
-DSQLITE_OMIT_UTF16 \
|
||||
-DSQLITE_OMIT_SHARED_CACHE \
|
||||
-DSQLITE_OMIT_WAL \
|
||||
-DSQLITE_THREADSAFE=0 \
|
||||
-DSQLITE_TEMP_STORE=2 \
|
||||
-DSQLITE_OS_KV_OPTIONAL=1 \
|
||||
@@ -187,6 +186,12 @@ SQLITE_OPT = \
|
||||
-DSQLITE_USE_URI=1 \
|
||||
-DSQLITE_WASM_ENABLE_C_TESTS \
|
||||
-DSQLITE_C=$(sqlite3.c)
|
||||
#SQLITE_OPT += -DSQLITE_DEBUG
|
||||
# Enabling SQLITE_DEBUG will break sqlite3_wasm_vfs_create_file()
|
||||
# (and thus sqlite3_js_vfs_create_file()). Those functions are
|
||||
# deprecated and alternatives are in place, but this crash behavior
|
||||
# can be used to find errant uses of sqlite3_js_vfs_create_file()
|
||||
# in client code.
|
||||
|
||||
.NOTPARALLEL: $(sqlite3.h)
|
||||
$(sqlite3.h):
|
||||
|
@@ -608,6 +608,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
["sqlite3_wasm_db_vfs", "sqlite3_vfs*", "sqlite3*","string"],
|
||||
["sqlite3_wasm_vfs_create_file", "int",
|
||||
"sqlite3_vfs*","string","*", "int"],
|
||||
["sqlite3_wasm_posix_create_file", "int", "string","*", "int"],
|
||||
["sqlite3_wasm_vfs_unlink", "int", "sqlite3_vfs*","string"]
|
||||
];
|
||||
|
||||
|
@@ -1357,6 +1357,74 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
};
|
||||
|
||||
/**
|
||||
If the current environment supports the POSIX file APIs, this routine
|
||||
creates (or overwrites) the given file using those APIs. This is
|
||||
primarily intended for use in Emscripten-based builds where the POSIX
|
||||
APIs are transparently proxied by an in-memory virtual filesystem.
|
||||
It may behave diffrently in other environments.
|
||||
|
||||
The first argument must be either a JS string or WASM C-string
|
||||
holding the filename. Note that this routine does _not_ create
|
||||
intermediary directories if the filename has a directory part.
|
||||
|
||||
The 2nd argument may either a valid WASM memory pointer, an
|
||||
ArrayBuffer, or a Uint8Array. The 3rd must be the length, in
|
||||
bytes, of the data array to copy. If the 2nd argument is an
|
||||
ArrayBuffer or Uint8Array and the 3rd is not a positive integer
|
||||
then the 3rd defaults to the array's byteLength value.
|
||||
|
||||
Results are undefined if data is a WASM pointer and dataLen is
|
||||
exceeds data's bounds.
|
||||
|
||||
Throws if any arguments are invalid or if creating or writing to
|
||||
the file fails.
|
||||
|
||||
Added in 3.43 as an alternative for the deprecated
|
||||
sqlite3_js_vfs_create_file().
|
||||
*/
|
||||
capi.sqlite3_js_posix_create_file = function(filename, data, dataLen){
|
||||
let pData;
|
||||
if(data && wasm.isPtr(data)){
|
||||
pData = data;
|
||||
}else if(data instanceof ArrayBuffer || data instanceof Uint8Array){
|
||||
pData = wasm.allocFromTypedArray(data);
|
||||
if(arguments.length<3 || !util.isInt32(dataLen) || dataLen<0){
|
||||
dataLen = data.byteLength;
|
||||
}
|
||||
}else{
|
||||
SQLite3Error.toss("Invalid 2nd argument for sqlite3_js_posix_create_file().");
|
||||
}
|
||||
try{
|
||||
if(!util.isInt32(dataLen) || dataLen<0){
|
||||
SQLite3Error.toss("Invalid 3rd argument for sqlite3_js_posix_create_file().");
|
||||
}
|
||||
const rc = wasm.sqlite3_wasm_posix_create_file(filename, pData, dataLen);
|
||||
if(rc) SQLite3Error.toss("Creation of file failed with sqlite3 result code",
|
||||
capi.sqlite3_js_rc_str(rc));
|
||||
}finally{
|
||||
wasm.dealloc(pData);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Deprecation warning: this function does not work properly in
|
||||
debug builds of sqlite3 because its out-of-scope use of the
|
||||
sqlite3_vfs API triggers assertions in the core library. That
|
||||
was unfortunately not discovered until 2023-08-11. This function
|
||||
is now deprecated and should not be used in new code.
|
||||
|
||||
Alternative options:
|
||||
|
||||
- "unix" VFS and its variants can get equivalent functionality
|
||||
with sqlite3_js_posix_create_file().
|
||||
|
||||
- OPFS: use either sqlite3.oo1.OpfsDb.importDb(), for the "opfs"
|
||||
VFS, or the importDb() method of the PoolUtil object provided
|
||||
by the "opfs-sahpool" OPFS (noting that its VFS name may differ
|
||||
depending on client-side configuration). We cannot proxy those
|
||||
from here because the former is necessarily asynchronous and
|
||||
the latter requires information not available to this function.
|
||||
|
||||
Creates a file using the storage appropriate for the given
|
||||
sqlite3_vfs. The first argument may be a VFS name (JS string
|
||||
only, NOT a WASM C-string), WASM-managed `sqlite3_vfs*`, or
|
||||
@@ -1402,9 +1470,13 @@ globalThis.sqlite3ApiBootstrap = function sqlite3ApiBootstrap(
|
||||
VFS nor the WASM environment imposes requirements which break it.
|
||||
|
||||
- "opfs": uses OPFS storage and creates directory parts of the
|
||||
filename.
|
||||
filename. It can only be used to import an SQLite3 database
|
||||
file and will fail if given anything else.
|
||||
*/
|
||||
capi.sqlite3_js_vfs_create_file = function(vfs, filename, data, dataLen){
|
||||
config.warn("sqlite3_js_vfs_create_file() is deprecated and",
|
||||
"should be avoided because it can lead to C-level crashes.",
|
||||
"See its documentation for alternative options.");
|
||||
let pData;
|
||||
if(data){
|
||||
if(wasm.isPtr(data)){
|
||||
|
@@ -1168,11 +1168,41 @@ const installOpfsVfs = function callee(options){
|
||||
doDir(opt.directory, 0);
|
||||
};
|
||||
|
||||
//TODO to support fiddle and worker1 db upload:
|
||||
//opfsUtil.createFile = function(absName, content=undefined){...}
|
||||
//We have sqlite3.wasm.sqlite3_wasm_vfs_create_file() for this
|
||||
//purpose but its interface and name are still under
|
||||
//consideration.
|
||||
/**
|
||||
Asynchronously imports the given bytes (a byte array or
|
||||
ArrayBuffer) into the given database file.
|
||||
|
||||
It very specifically requires the input to be an SQLite3
|
||||
database and throws if that's not the case. It does so in
|
||||
order to prevent this function from taking on a larger scope
|
||||
than it is specifically intended to. i.e. we do not want it to
|
||||
become a convenience for importing arbitrary files into OPFS.
|
||||
|
||||
Throws on error. Resolves to the number of bytes written.
|
||||
*/
|
||||
opfsUtil.importDb = async function(filename, bytes){
|
||||
if(bytes instanceof ArrayBuffer) bytes = new Uint8Array(bytes);
|
||||
const n = bytes.byteLength;
|
||||
if(n<512 || n%512!=0){
|
||||
toss("Byte array size is invalid for an SQLite db.");
|
||||
}
|
||||
const header = "SQLite format 3";
|
||||
for(let i = 0; i < header.length; ++i){
|
||||
if( header.charCodeAt(i) !== bytes[i] ){
|
||||
toss("Input does not contain an SQLite database header.");
|
||||
}
|
||||
}
|
||||
const [hDir, fnamePart] = await opfsUtil.getDirForFilename(filename, true);
|
||||
const hFile = await hDir.getFileHandle(fnamePart, {create:true});
|
||||
const sah = await hFile.createSyncAccessHandle();
|
||||
sah.truncate(0);
|
||||
const nWrote = sah.write(bytes, {at: 0});
|
||||
sah.close();
|
||||
if(nWrote != n){
|
||||
toss("Expected to write "+n+" bytes but wrote "+nWrote+".");
|
||||
}
|
||||
return nWrote;
|
||||
};
|
||||
|
||||
if(sqlite3.oo1){
|
||||
const OpfsDb = function(...args){
|
||||
@@ -1182,6 +1212,7 @@ const installOpfsVfs = function callee(options){
|
||||
};
|
||||
OpfsDb.prototype = Object.create(sqlite3.oo1.DB.prototype);
|
||||
sqlite3.oo1.OpfsDb = OpfsDb;
|
||||
OpfsDb.importDb = opfsUtil.importDb;
|
||||
sqlite3.oo1.DB.dbCtorHelper.setVfsPostOpenSql(
|
||||
opfsVfs.pointer,
|
||||
function(oo1Db, sqlite3){
|
||||
|
@@ -141,9 +141,6 @@
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
# define SQLITE_OMIT_UTF16 1
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
# define SQLITE_OMIT_WAL 1
|
||||
#endif
|
||||
#ifndef SQLITE_OS_KV_OPTIONAL
|
||||
# define SQLITE_OS_KV_OPTIONAL 1
|
||||
#endif
|
||||
@@ -295,7 +292,7 @@ SQLITE_WASM_EXPORT void * sqlite3_wasm_pstack_ptr(void){
|
||||
*/
|
||||
SQLITE_WASM_EXPORT void sqlite3_wasm_pstack_restore(unsigned char * p){
|
||||
assert(p>=PStack.pBegin && p<=PStack.pEnd && p>=PStack.pPos);
|
||||
assert(0==(p & 0x7));
|
||||
assert(0==((unsigned long long)p & 0x7));
|
||||
if(p>=PStack.pBegin && p<=PStack.pEnd /*&& p>=PStack.pPos*/){
|
||||
PStack.pPos = p;
|
||||
}
|
||||
@@ -1353,6 +1350,13 @@ int sqlite3_wasm_db_serialize( sqlite3 *pDb, const char *zSchema,
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** ACHTUNG: it was discovered on 2023-08-11 that, with SQLITE_DEBUG,
|
||||
** this function's out-of-scope use of the sqlite3_vfs/file/io_methods
|
||||
** APIs leads to triggering of assertions in the core library. Its use
|
||||
** is now deprecated and VFS-specific APIs for importing files need to
|
||||
** be found to replace it. sqlite3_wasm_posix_create_file() is
|
||||
** suitable for the "unix" family of VFSes.
|
||||
**
|
||||
** Creates a new file using the I/O API of the given VFS, containing
|
||||
** the given number of bytes of the given data. If the file exists, it
|
||||
** is truncated to the given length and populated with the given
|
||||
@@ -1398,7 +1402,14 @@ int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
int rc;
|
||||
sqlite3_file *pFile = 0;
|
||||
sqlite3_io_methods const *pIo;
|
||||
const int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE;
|
||||
const int openFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
|
||||
#if 0 && defined(SQLITE_DEBUG)
|
||||
| SQLITE_OPEN_MAIN_JOURNAL
|
||||
/* ^^^^ This is for testing a horrible workaround to avoid
|
||||
triggering a specific assert() in os_unix.c:unixOpen(). Please
|
||||
do not enable this in real builds. */
|
||||
#endif
|
||||
;
|
||||
int flagsOut = 0;
|
||||
int fileExisted = 0;
|
||||
int doUnlock = 0;
|
||||
@@ -1464,6 +1475,34 @@ int sqlite3_wasm_vfs_create_file( sqlite3_vfs *pVfs,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
**
|
||||
** Creates or overwrites a file using the POSIX file API,
|
||||
** i.e. Emscripten's virtual filesystem. Creates or truncates
|
||||
** zFilename, appends pData bytes to it, and returns 0 on success or
|
||||
** SQLITE_IOERR on error.
|
||||
*/
|
||||
SQLITE_WASM_EXPORT
|
||||
int sqlite3_wasm_posix_create_file( const char *zFilename,
|
||||
const unsigned char * pData,
|
||||
int nData ){
|
||||
int rc;
|
||||
FILE * pFile = 0;
|
||||
int fileExisted = 0;
|
||||
size_t nWrote = 1;
|
||||
|
||||
if( !zFilename || nData<0 || (pData==0 && nData>0) ) return SQLITE_MISUSE;
|
||||
pFile = fopen(zFilename, "w");
|
||||
if( 0==pFile ) return SQLITE_IOERR;
|
||||
if( nData>0 ){
|
||||
nWrote = fwrite(pData, (size_t)nData, 1, pFile);
|
||||
}
|
||||
fclose(pFile);
|
||||
return 1==nWrote ? 0 : SQLITE_IOERR;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is NOT part of the sqlite3 public API. It is strictly
|
||||
** for use by the sqlite project's own JS/WASM bindings.
|
||||
|
@@ -355,6 +355,7 @@
|
||||
sqlite3_js_db_vfs: 'wasm:/api-c-style.md#sqlite3_js_db_vfs',
|
||||
sqlite3_js_kvvfs_clear: 'wasm:/api-c-style.md#sqlite3_js_kvvfs',
|
||||
sqlite3_js_kvvfs_size: 'wasm:/api-c-style.md#sqlite3_js_kvvfs',
|
||||
sqlite3_js_posix_create_file: 'wasm:/api-c-style.md#sqlite3_js_posix_create_file',
|
||||
sqlite3_js_rc_str: 'wasm:/api-c-style.md#sqlite3_js_rc_str',
|
||||
sqlite3_js_vfs_create_file: 'wasm:/api-c-style.md#sqlite3_js_vfs_create_file',
|
||||
sqlite3_js_vfs_list: 'wasm:/api-c-style.md#sqlite3_js_vfs_list',
|
||||
|
@@ -1671,13 +1671,12 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}
|
||||
}/*sqlite3_js_db_export()*/)
|
||||
.t({
|
||||
name: 'sqlite3_js_vfs_create_file() with db in default VFS',
|
||||
name: 'sqlite3_js_posix_create_file()',
|
||||
predicate: ()=>true,
|
||||
test: function(sqlite3){
|
||||
const db = this.db;
|
||||
const pVfs = capi.sqlite3_js_db_vfs(db);
|
||||
const filename = "sqlite3_js_vfs_create_file().db";
|
||||
capi.sqlite3_js_vfs_create_file(pVfs, filename, this.dbExport);
|
||||
const filename = "sqlite3_js_posix_create_file.db";
|
||||
capi.sqlite3_js_posix_create_file(filename, this.dbExport);
|
||||
delete this.dbExport;
|
||||
const db2 = new sqlite3.oo1.DB(filename,'r');
|
||||
try {
|
||||
@@ -1686,7 +1685,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
T.assert(n>0 && db2.selectValue(sql) === n);
|
||||
}finally{
|
||||
db2.close();
|
||||
wasm.sqlite3_wasm_vfs_unlink(pVfs, filename);
|
||||
wasm.sqlite3_wasm_vfs_unlink(0, filename);
|
||||
}
|
||||
}
|
||||
}/*sqlite3_js_vfs_create_file()*/)
|
||||
@@ -2907,7 +2906,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
.t({
|
||||
name: 'OPFS db sanity checks',
|
||||
test: async function(sqlite3){
|
||||
const filename = this.opfsDbFile = 'sqlite3-tester1.db';
|
||||
const filename = this.opfsDbFile = '/dir/sqlite3-tester1.db';
|
||||
const pVfs = this.opfsVfs = capi.sqlite3_vfs_find('opfs');
|
||||
T.assert(pVfs);
|
||||
const unlink = this.opfsUnlink =
|
||||
@@ -2935,22 +2934,23 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
}
|
||||
}/*OPFS db sanity checks*/)
|
||||
.t({
|
||||
name: 'OPFS export/import',
|
||||
name: 'OPFS import',
|
||||
test: async function(sqlite3){
|
||||
let db;
|
||||
try {
|
||||
const exp = this.opfsDbExport;
|
||||
delete this.opfsDbExport;
|
||||
capi.sqlite3_js_vfs_create_file("opfs", this.opfsDbFile, exp);
|
||||
const db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
|
||||
T.assert(6 === db.selectValue('select count(*) from p'));
|
||||
this.opfsImportSize = await sqlite3.oo1.OpfsDb.importDb(this.opfsDbFile, exp);
|
||||
db = new sqlite3.oo1.OpfsDb(this.opfsDbFile);
|
||||
T.assert(6 === db.selectValue('select count(*) from p')).
|
||||
assert( this.opfsImportSize == exp.byteLength );
|
||||
}finally{
|
||||
if(db) db.close();
|
||||
}
|
||||
}
|
||||
}/*OPFS export/import*/)
|
||||
.t({
|
||||
name: 'OPFS utility APIs and sqlite3_js_vfs_create_file()',
|
||||
name: '(Internal-use) OPFS utility APIs',
|
||||
test: async function(sqlite3){
|
||||
const filename = this.opfsDbFile;
|
||||
const pVfs = this.opfsVfs;
|
||||
@@ -2959,8 +2959,6 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
delete this.opfsDbFile;
|
||||
delete this.opfsVfs;
|
||||
delete this.opfsUnlink;
|
||||
unlink();
|
||||
// Sanity-test sqlite3_js_vfs_create_file()...
|
||||
/**************************************************************
|
||||
ATTENTION CLIENT-SIDE USERS: sqlite3.opfs is NOT intended
|
||||
for client-side use. It is only for this project's own
|
||||
@@ -2968,39 +2966,19 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
any time.
|
||||
***************************************************************/
|
||||
const opfs = sqlite3.opfs;
|
||||
const fSize = 1379;
|
||||
const fSize = this.opfsImportSize;
|
||||
delete this.opfsImportSize;
|
||||
let sh;
|
||||
try{
|
||||
T.assert(!(await opfs.entryExists(filename)));
|
||||
capi.sqlite3_js_vfs_create_file(
|
||||
pVfs, filename, null, fSize
|
||||
);
|
||||
T.assert(await opfs.entryExists(filename));
|
||||
let fh = await opfs.rootDirectory.getFileHandle(filename);
|
||||
const [dirHandle, filenamePart] = await opfs.getDirForFilename(filename, false);
|
||||
const fh = await dirHandle.getFileHandle(filenamePart);
|
||||
sh = await fh.createSyncAccessHandle();
|
||||
T.assert(fSize === await sh.getSize());
|
||||
await sh.close();
|
||||
sh = undefined;
|
||||
unlink();
|
||||
T.assert(!(await opfs.entryExists(filename)));
|
||||
|
||||
const ba = new Uint8Array([1,2,3,4,5]);
|
||||
capi.sqlite3_js_vfs_create_file(
|
||||
"opfs", filename, ba
|
||||
);
|
||||
T.assert(await opfs.entryExists(filename));
|
||||
fh = await opfs.rootDirectory.getFileHandle(filename);
|
||||
sh = await fh.createSyncAccessHandle();
|
||||
T.assert(ba.byteLength === await sh.getSize());
|
||||
await sh.close();
|
||||
sh = undefined;
|
||||
unlink();
|
||||
|
||||
T.mustThrowMatching(()=>{
|
||||
capi.sqlite3_js_vfs_create_file(
|
||||
"no-such-vfs", filename, ba
|
||||
);
|
||||
}, "SQLITE_NOTFOUND: Unknown sqlite3_vfs name: no-such-vfs");
|
||||
}finally{
|
||||
if(sh) await sh.close();
|
||||
unlink();
|
||||
@@ -3103,7 +3081,7 @@ globalThis.sqlite3InitModule = sqlite3InitModule;
|
||||
const conf2 = JSON.parse(JSON.stringify(sahPoolConfig));
|
||||
conf2.name += '-test2';
|
||||
const POther = await inst(conf2);
|
||||
log("Installed second SAH instance as",conf2.name);
|
||||
//log("Installed second SAH instance as",conf2.name);
|
||||
T.assert(0 === POther.getFileCount())
|
||||
.assert(true === await POther.removeVfs());
|
||||
|
||||
|
55
manifest
55
manifest
@@ -1,11 +1,11 @@
|
||||
C Fix\sa\smakefile\sdeps\sproblem\swhich\scaused\sext/jni\sbuild\sto\sfail\sif\ssqlite3.c/h\swere\snot\screated\sbeforehand.
|
||||
D 2023-08-11T20:32:40.205
|
||||
C Merge\strunk\sinto\sjni\sbranch.
|
||||
D 2023-08-11T21:24:08.276
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
F Makefile.in 5ad2d1e198306bc730f06f7545d3a8832225b1bfddbc648d97c0e0b9a35f67e9
|
||||
F Makefile.linux-gcc f3842a0b1efbfbb74ac0ef60e56b301836d05b4d867d014f714fa750048f1ab6
|
||||
F Makefile.msc 7248d860f71ab164b4cec3c415e6cc1bd9fee860c370d65bd8bb49e9572521e2
|
||||
F Makefile.msc daad4a19e0b3c3c3b79b64d4ddbf75e3f506405e8d3f3f604d6f48b26043c51f
|
||||
F README.md c1c4218efcc4071a6e26db2b517fdbc1035696a29b370edd655faddbef02b224
|
||||
F VERSION c6366dc72582d3144ce87b013cc35fe48d62f6d07d5be0c9716ea33c862144aa
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
@@ -15,7 +15,7 @@ F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
F autoconf/INSTALL 83e4a25da9fd053c7b3665eaaaf7919707915903
|
||||
F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
|
||||
F autoconf/Makefile.fallback 22fe523eb36dfce31e0f6349f782eb084e86a5620b2b0b4f84a2d6133f53f5ac
|
||||
F autoconf/Makefile.msc 20366d19fbfc3fceecce95344a2114069eaab4fc22e4f02430da167a1e2ddf04
|
||||
F autoconf/Makefile.msc 00f11ce1f7904416fe841c33e7d789defe8c39e1df6b97e93ed2af3b1bbaf9d7
|
||||
F autoconf/README.first 6c4f34fe115ff55d4e8dbfa3cecf04a0188292f7
|
||||
F autoconf/README.txt 42cfd21d0b19dc7d5d85fb5c405c5f3c6a4c923021c39128f6ba685355d8fd56
|
||||
F autoconf/configure.ac ec7fa914c5e74ff212fe879f9bb6918e1234497e05facfb641f30c4d5893b277
|
||||
@@ -528,7 +528,7 @@ F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
|
||||
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
|
||||
F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865f002fc80cb
|
||||
F ext/wasm/EXPORTED_FUNCTIONS.fiddle.in 27450c8b8c70875a260aca55435ec927068b34cef801a96205adb81bdcefc65c
|
||||
F ext/wasm/GNUmakefile 50a4bd40ee01a90badfc28d0042789740e47e2855d3b9acaa8801b6dc2763aba
|
||||
F ext/wasm/GNUmakefile 8159bc5f9433fe21022c1a8e8c30cb1a523530ba9ef53bdf5d1e0a2186554806
|
||||
F ext/wasm/README-dist.txt 6382cb9548076fca472fb3330bbdba3a55c1ea0b180ff9253f084f07ff383576
|
||||
F ext/wasm/README.md a8a2962c3aebdf8d2104a9102e336c5554e78fc6072746e5daf9c61514e7d193
|
||||
F ext/wasm/api/EXPORTED_FUNCTIONS.sqlite3-api d6a5078f48a5301ed17b9a30331075d9b2506e1360c1f0dee0c7816c10acd9ab
|
||||
@@ -541,16 +541,16 @@ F ext/wasm/api/post-js-footer.js cd0a8ec768501d9bd45d325ab0442037fb0e33d1f3b4f08
|
||||
F ext/wasm/api/post-js-header.js 47b6b281f39ad59fa6e8b658308cd98ea292c286a68407b35ff3ed9cfd281a62
|
||||
F ext/wasm/api/pre-js.c-pp.js ad906703f7429590f2fbf5e6498513bf727a1a4f0ebfa057afb08161d7511219
|
||||
F ext/wasm/api/sqlite3-api-cleanup.js d235ad237df6954145404305040991c72ef8b1881715d2a650dda7b3c2576d0e
|
||||
F ext/wasm/api/sqlite3-api-glue.js cc6b0bb093bdb6279d4af259200b7b9e150e3796a8a3a4cd09a4928c43d25e56
|
||||
F ext/wasm/api/sqlite3-api-glue.js b65e546568f1dfb35205b9792feb5146a6323d71b55cda58e2ed30def6dd52f3
|
||||
F ext/wasm/api/sqlite3-api-oo1.js 9678dc4d9a5d39632b6ffe6ea94a023119260815bf32f265bf5f6c36c9516db8
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 76258e160bf6a89cc75a7d3c05646a054c8cab7219cd1e10bc20cacaad022131
|
||||
F ext/wasm/api/sqlite3-api-prologue.js 5f283b096b98bfb1ee2f2201e7ff0489dff00e29e1030c30953bdb4f5b87f4bd
|
||||
F ext/wasm/api/sqlite3-api-worker1.js 9f32af64df1a031071912eea7a201557fe39b1738645c0134562bb84e88e2fec
|
||||
F ext/wasm/api/sqlite3-license-version-header.js 0c807a421f0187e778dc1078f10d2994b915123c1223fe752b60afdcd1263f89
|
||||
F ext/wasm/api/sqlite3-opfs-async-proxy.js 8cf8a897726f14071fae6be6648125162b256dfb4f96555b865dbb7a6b65e379
|
||||
F ext/wasm/api/sqlite3-v-helper.js 7daa0eab0a513a25b05e9abae7b5beaaa39209b3ed12f86aeae9ef8d2719ed25
|
||||
F ext/wasm/api/sqlite3-vfs-opfs-sahpool.c-pp.js abb69b5e008961026bf5ff433d7116cb046359af92a5daf73208af2e7ac80ae7
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e7a690e0e78ff4d563f2eca468f91db69f001ff4b79c6d2304cbb6f62dca437d
|
||||
F ext/wasm/api/sqlite3-wasm.c 8867f1d41c112fb4a2cfe22ff224eccaf309fcdea266cee0ec554f85db72ef0f
|
||||
F ext/wasm/api/sqlite3-vfs-opfs.c-pp.js e04fc2fda6a0200ef80efdbb4ddfa0254453558adb17ec3a230f93d2bf1d711c
|
||||
F ext/wasm/api/sqlite3-wasm.c d4d4c2b349b43b7b861e6d2994299630fb79e07573ea6b61e28e8071b7d16b61
|
||||
F ext/wasm/api/sqlite3-worker1-promiser.c-pp.js bc06df0d599e625bde6a10a394e326dc68da9ff07fa5404354580f81566e591f
|
||||
F ext/wasm/api/sqlite3-worker1.c-pp.js da509469755035e919c015deea41b4514b5e84c12a1332e6cc8d42cb2cc1fb75
|
||||
F ext/wasm/batch-runner.html 4deeed44fe41496dc6898d9fb17938ea3291f40f4bfb977e29d0cef96fbbe4c8
|
||||
@@ -580,7 +580,7 @@ F ext/wasm/index-dist.html 22379774f0ad4edcaaa8cf9c674c82e794cc557719a8addabed74
|
||||
F ext/wasm/index.html 4e7847b909f4ae0da8c829b150b79454050e53b3658431f138636257729cd42b
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.js 1264710db3cfbcb6887d95665b7aeba60c1126eaef789ca4cf1a4a17d5bc7f54
|
||||
F ext/wasm/jaccwabyt/jaccwabyt.md 37911f00db12cbcca73aa1ed72594430365f30aafae2fa9c886961de74e5e0eb
|
||||
F ext/wasm/module-symbols.html 841de62fc198988b8330e238c260e70ec93028b096e1a1234db31b187a899d10
|
||||
F ext/wasm/module-symbols.html dc476b403369b26a1a23773e13b80f41b9a49f0825e81435fe3600a7cfbbe337
|
||||
F ext/wasm/scratchpad-wasmfs.html a3d7388f3c4b263676b58b526846e9d02dfcb4014ff29d3a5040935286af5b96
|
||||
F ext/wasm/scratchpad-wasmfs.mjs 66034b9256b218de59248aad796760a1584c1dd842231505895eff00dbd57c63
|
||||
F ext/wasm/speedtest1-wasmfs.html 0e9d335a9b5b5fafe6e1bc8dc0f0ca7e22e6eb916682a2d7c36218bb7d67379d
|
||||
@@ -595,7 +595,7 @@ F ext/wasm/test-opfs-vfs.html 1f2d672f3f3fce810dfd48a8d56914aba22e45c6834e262555
|
||||
F ext/wasm/test-opfs-vfs.js f09266873e1a34d9bdb6d3981ec8c9e382f31f215c9fd2f9016d2394b8ae9b7b
|
||||
F ext/wasm/tester1-worker.html ebc4b820a128963afce328ecf63ab200bd923309eb939f4110510ab449e9814c
|
||||
F ext/wasm/tester1.c-pp.html 1c1bc78b858af2019e663b1a31e76657b73dc24bede28ca92fbe917c3a972af2
|
||||
F ext/wasm/tester1.c-pp.js b88dcad5424a652e8204c44a71bbc3deb22a4922c97ba792aedbabb7a6827b91
|
||||
F ext/wasm/tester1.c-pp.js 64eb0ee6e695d5638d0f758f31a0ca2231e627ca5d768de3d8b44f9f494de8d4
|
||||
F ext/wasm/tests/opfs/concurrency/index.html 0802373d57034d51835ff6041cda438c7a982deea6079efd98098d3e42fbcbc1
|
||||
F ext/wasm/tests/opfs/concurrency/test.js a98016113eaf71e81ddbf71655aa29b0fed9a8b79a3cdd3620d1658eb1cc9a5d
|
||||
F ext/wasm/tests/opfs/concurrency/worker.js 0a8c1a3e6ebb38aabbee24f122693f1fb29d599948915c76906681bb7da1d3d2
|
||||
@@ -628,7 +628,7 @@ F src/btreeInt.h 91a9e0c41a0e71fa91a742ec285c63dd8dcb38b73d14fae0ed7209174ff0fdc
|
||||
F src/build.c a8ae3b32d9aa9bbd2c0e97d7c0dd80def9fbca408425de1608f57ee6f47f45f4
|
||||
F src/callback.c db3a45e376deff6a16c0058163fe0ae2b73a2945f3f408ca32cf74960b28d490
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c 20507cc0b0a6c19cd882fcd0eaeda32ae6a4229fb4b024cfdf3183043d9b703d
|
||||
F src/ctime.c cff2b493de894383832347c3a3f936a05f4e089a92b42366838da1735f3848b5
|
||||
F src/date.c f73f203b3877cef866c60ab402aec2bf89597219b60635cf50cbe3c5e4533e94
|
||||
F src/dbpage.c f3eea5f7ec47e09ee7da40f42b25092ecbe961fc59566b8e5f705f34335b2387
|
||||
F src/dbstat.c ec92074baa61d883de58c945162d9e666c13cd7cf3a23bc38b4d1c4d0b2c2bef
|
||||
@@ -643,7 +643,7 @@ F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/json.c 9c231a853268ce6aee2e300e26d4445ba42117374a2275f8e9537b2f912909d6
|
||||
F src/json.c ae840f87b418f039f5d336b488933d09396bd31e6b31e855b93055ccaee4e255
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
|
||||
F src/main.c fde8f13c876a658b4e8b74b77d875ca887915c174ea6a2f3122d80966f93d865
|
||||
@@ -670,8 +670,8 @@ F src/os_setup.h 6011ad7af5db4e05155f385eb3a9b4470688de6f65d6166b8956e58a3d87210
|
||||
F src/os_unix.c 2e8b12107f75d1bd16412f312b4c5d5103191807a37836d3b81beb26436ad81b
|
||||
F src/os_win.c 7038223a1cda0a47e2ab4db47f63bf1833fe53ba0542f0f283a062ea13894103
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c 5ddf3a74c633a008ea6b2f5b3186167e88e2c8ca8a252ecab06ab3f1eb48e60f
|
||||
F src/pager.h f82e9844166e1585f5786837ddc7709966138ced17f568c16af7ccf946c2baa3
|
||||
F src/pager.c 993445a19b611d473ca007542ab3149840661a4c7e9f2d9e1ec008b7cc2abe78
|
||||
F src/pager.h 6e326bd05970a24dd28d41d3980b6964fbaa37b4da54a2c0d4e0c5bdb06ff187
|
||||
F src/parse.y aeb7760d41cfa86465e3adba506500c021597049fd55f82a30e5b7045862c28c
|
||||
F src/pcache.c 4cd4a0043167da9ba7e19b4d179a0e6354e7fe32c16f781ecf9bf0a5ff63b40b
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
@@ -685,7 +685,7 @@ F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 5f545a2c8702d4d3430bbb188cfec47d6c122d899061ef00cbe56af14591c574
|
||||
F src/shell.c.in 694aaf751f00610381533d4a31c83d142cfc83ef91ef65e2aa6912ace7c39b40
|
||||
F src/sqlite.h.in 7b07a33d2af82ee974aa91e6294abce0282b2f4c5934b291d2fff961810dd867
|
||||
F src/sqlite.h.in 73a366c1c45d5ac9888cfe81c458826a44498531d106cfb4f328193ab5f6f17d
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
|
||||
F src/sqliteInt.h 025ed58a41968ef80d64cdc194caa8dd207b0256b147253d762fdac7a62408f9
|
||||
@@ -745,19 +745,19 @@ F src/test_windirent.h da2e5b73c32d09905fbdd00f27cd802212a32a58ead882736fe4f5eb7
|
||||
F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
|
||||
F src/tokenize.c 0fb405f9adf3f757c26bfc1ae6d58ac5dccbb918917ba9e5ef0e6673a06563d3
|
||||
F src/tokenize.c 23d9f4539880b40226254ad9072f4ecf12eb1902e62aea47aac29928afafcfd5
|
||||
F src/treeview.c 1d52fbc4e97161e65858d36e3424ea6e3fc045dd8a679c82b4b9593dc30de3bd
|
||||
F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
|
||||
F src/update.c 0bb9171afaa4d0b100ad946873bccda7aef90ffe083ef5c63668fce08c4df9da
|
||||
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c b3532a95ad56db67b3acd3955e688e4cb80ebec6fd1f459a8eb51cceedd6de69
|
||||
F src/util.c a40062117e705eb3339201842717a022092816b92479eead6397cde28af32ff9
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c 346d848a0bf8128e3e3722c5406f4bde6c32d7093b93402c6f8e0718d19305c3
|
||||
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
|
||||
F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
|
||||
F src/vdbeapi.c f37822f215740ede2a8fcae99bc13f2cc3a72dd0e1d22b81b9298c5ca67dbc38
|
||||
F src/vdbeaux.c a586f445945eef6ad1fcd7c94f700faa1baea93c0dbd446291c7cf65966c8470
|
||||
F src/vdbeaux.c e3aa5c46827cd95e0fc4d0f302fa3e901ab5f07258fdbb42709eeef40f63018d
|
||||
F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce
|
||||
F src/vdbemem.c 317b9f48708139db6239ade40c7980b4bc8233168383690d588dad6d8437f722
|
||||
F src/vdbesort.c 0d40dca073c94e158ead752ef4225f4fee22dee84145e8c00ca2309afb489015
|
||||
@@ -765,8 +765,8 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8
|
||||
F src/vdbevtab.c 57fa8f56478e5b5cb558cb425e7878515e0a105c54f96f1d1bbf4b9433529254
|
||||
F src/vtab.c 1ecf8c3745d29275688d583e12822fa984d421e0286b5ef50c137bc3bf6d7a64
|
||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c dd843f619ac60d5dadab7109cf402432ba74dde0c301505fd1c202add07659e3
|
||||
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||
F src/wal.c 02e10f033a6972bc7d50122b400318003199c504cda48f61ad404564505f4e89
|
||||
F src/wal.h 04a9e53121d5076f2a173b0f2facb39d33047093fee71bd3bbe6b1f6f1f5fd4b
|
||||
F src/walker.c 7c7ea0115345851c3da4e04e2e239a29983b61fb5b038b94eede6aba462640e2
|
||||
F src/where.c b8917792f1e0dbfa28fb29e6cd3d560060d69667be0ba4c491cbc772363264f5
|
||||
F src/whereInt.h c7d19902863beadec1d04e66aca39c0bcd60b74f05f0eaa7422c7005dfc5d51a
|
||||
@@ -1272,7 +1272,7 @@ F test/json/README.md 63e3e589e1df8fd3cc1588ba1faaff659214003f8b77a15af5c6452b35
|
||||
F test/json/json-generator.tcl dc0dd0f393800c98658fc4c47eaa6af29d4e17527380cd28656fb261bddc8a3f
|
||||
F test/json/json-q1.txt 65f9d1cdcc4cffa9823fb73ed936aae5658700cd001fde448f68bfb91c807307
|
||||
F test/json/json-speed-check.sh 8b7babf530faa58bd59d6d362cec8e9036a68c5457ff46f3b1f1511d21af6737 x
|
||||
F test/json101.test 94126d4291d4a00e45f6988ce885c410de69243490e46e70e9946cb6e6f9ea02
|
||||
F test/json101.test 243b0a2650218ac5eafde6ce2a92a0e9d02bf24f62aec68693b69d9a693f120a
|
||||
F test/json102.test 24f6f204f9cde45b971016691d0b92a9b4c58040d699e36d6b12cb165f9083ff
|
||||
F test/json103.test 53df87f83a4e5fa0c0a56eb29ff6c94055c6eb919f33316d62161a8880112dbe
|
||||
F test/json104.test 1b844a70cddcfa2e4cd81a5db0657b2e61e7f00868310f24f56a9ba0114348c1
|
||||
@@ -1538,7 +1538,7 @@ F test/snapshot.test a504f2e7009f512ef66c719f0ea1c55a556bdaf1e1312c80a04d46fc1a3
|
||||
F test/snapshot2.test 8d6ff5dd9cc503f6e12d408a30409c3f9c653507b24408d9cd7195931c89bc54
|
||||
F test/snapshot3.test 8744313270c55f6e18574283553d3c5c5fe4c5970585663613a0e75c151e599b
|
||||
F test/snapshot4.test d4e9347ef2fcabc491fc893506c7bbaf334da3be111d6eb4f3a97cc623b78322
|
||||
F test/snapshot_fault.test f6c5ef7cb93bf92fbb4e864ecc5c87df7d3a250064838822db5b4d3a5563ede4
|
||||
F test/snapshot_fault.test 129234ceb9b26a0e1000e8563a16e790f5c1412354e70749cbd78c3d5d07d60a
|
||||
F test/snapshot_up.test a0a29c4cf33475fcef07c3f8e64af795e24ab91b4cc68295863402a393cdd41c
|
||||
F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c
|
||||
F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087
|
||||
@@ -1898,6 +1898,7 @@ F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db8
|
||||
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
|
||||
F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc
|
||||
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
|
||||
F test/walseh1.test 82da37763b0d87942dccd191e58321532ce3d44b87ef36e04ff9ce13f382bbae
|
||||
F test/walsetlk.test 34c901443b31ab720afc463f5b236c86ca5c4134402573dce91aa0761de8db5a
|
||||
F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370dbc7a3
|
||||
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||
@@ -2012,7 +2013,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
|
||||
F tool/merge-test.tcl de76b62f2de2a92d4c1ca4f976bce0aea6899e0229e250479b229b2a1914b176
|
||||
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
|
||||
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
|
||||
F tool/mkctimec.tcl 38e3db33210a200aae791635125052a643a27aa0619a0debf19aa9c55e1b2dde x
|
||||
F tool/mkctimec.tcl aca4b83e49aecf10368cd5d11bc4847061041ade026db5bd8da17ef201f1403b x
|
||||
F tool/mkkeywordhash.c b9faa0ae7e14e4dbbcd951cddd786bf46b8a65bb07b129ba8c0cfade723aaffd
|
||||
F tool/mkmsvcmin.tcl 8897d515ef7f94772322db95a3b6fce6c614d84fe0bdd06ba5a1c786351d5a1d
|
||||
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
|
||||
@@ -2090,8 +2091,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 6c8538d83495ce65dbd7417263b3b06dbbb2a649e9a61a743911944599d75ffc
|
||||
R 00e08242dc8443215cfb70aa39f020b2
|
||||
P 101de670774f63757180282763730aa53e70198bd7a674c27e6044632d39d22a 8a6b0c24937e855b710f97b4aea973eff53e6d43e1182842731547aa4b37db2a
|
||||
R f0a8c88fe7b9660119e5c4d560adb197
|
||||
U stephan
|
||||
Z 4a14af7dfae41cdfaa811266b607e2bd
|
||||
Z b7f921f442de7d419e4b8b5ee576c27d
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@@ -1 +1 @@
|
||||
101de670774f63757180282763730aa53e70198bd7a674c27e6044632d39d22a
|
||||
4f0aeeba0287e846908180eab6f7080ebe1323ebe49340771864d110e1ca5b2b
|
@@ -60,9 +60,6 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
|
||||
"4_BYTE_ALIGNED_MALLOC",
|
||||
#endif
|
||||
#ifdef SQLITE_64BIT_STATS
|
||||
"64BIT_STATS",
|
||||
#endif
|
||||
#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
|
||||
# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
|
||||
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
|
||||
@@ -399,6 +396,9 @@ static const char * const sqlite3azCompileOpt[] = {
|
||||
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
|
||||
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
|
||||
#endif
|
||||
#ifdef SQLITE_LEGACY_JSON_VALID
|
||||
"LEGACY_JSON_VALID",
|
||||
#endif
|
||||
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
"LIKE_DOESNT_MATCH_BLOBS",
|
||||
#endif
|
||||
|
@@ -3009,7 +3009,13 @@ static void jsonValidFunc(
|
||||
){
|
||||
JsonParse *p; /* The parse */
|
||||
UNUSED_PARAMETER(argc);
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
||||
#ifdef SQLITE_LEGACY_JSON_VALID
|
||||
/* Incorrect legacy behavior was to return FALSE for a NULL input */
|
||||
sqlite3_result_int(ctx, 0);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
p = jsonParseCached(ctx, argv[0], 0, 0);
|
||||
if( p==0 || p->oom ){
|
||||
sqlite3_result_error_nomem(ctx);
|
||||
|
@@ -7729,4 +7729,10 @@ int sqlite3PagerWalFramesize(Pager *pPager){
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USE_SEH
|
||||
int sqlite3PagerWalSystemErrno(Pager *pPager){
|
||||
return sqlite3WalSystemErrno(pPager->pWal);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_OMIT_DISKIO */
|
||||
|
@@ -240,4 +240,8 @@ void sqlite3PagerRekey(DbPage*, Pgno, u16);
|
||||
# define enable_simulated_io_errors()
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USE_SEH
|
||||
int sqlite3PagerWalSystemErrno(Pager*);
|
||||
#endif
|
||||
|
||||
#endif /* SQLITE_PAGER_H */
|
||||
|
@@ -528,6 +528,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
|
||||
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
|
||||
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
|
||||
#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<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))
|
||||
|
@@ -433,7 +433,7 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){
|
||||
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
|
||||
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
|
||||
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
|
||||
testcase( z[0]=='9' );
|
||||
testcase( z[0]=='9' ); testcase( z[0]=='.' );
|
||||
*tokenType = TK_INTEGER;
|
||||
#ifndef SQLITE_OMIT_HEX_INTEGER
|
||||
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
|
||||
|
17
src/util.c
17
src/util.c
@@ -141,6 +141,23 @@ void sqlite3ErrorClear(sqlite3 *db){
|
||||
*/
|
||||
void sqlite3SystemError(sqlite3 *db, int rc){
|
||||
if( rc==SQLITE_IOERR_NOMEM ) return;
|
||||
#ifdef SQLITE_USE_SEH
|
||||
if( rc==SQLITE_IOERR_IN_PAGE ){
|
||||
int ii;
|
||||
int iErr;
|
||||
sqlite3BtreeEnterAll(db);
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
if( db->aDb[ii].pBt ){
|
||||
iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt));
|
||||
if( iErr ){
|
||||
db->iSysErrno = iErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeaveAll(db);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
rc &= 0xff;
|
||||
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
|
||||
db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
|
||||
|
@@ -3372,6 +3372,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
||||
sqlite3VdbeLeave(p);
|
||||
return SQLITE_BUSY;
|
||||
}else if( rc!=SQLITE_OK ){
|
||||
sqlite3SystemError(db, rc);
|
||||
p->rc = rc;
|
||||
sqlite3RollbackAll(db, SQLITE_OK);
|
||||
p->nChange = 0;
|
||||
|
439
src/wal.c
439
src/wal.c
@@ -528,7 +528,13 @@ struct Wal {
|
||||
u32 iReCksum; /* On commit, recalculate checksums from here */
|
||||
const char *zWalName; /* Name of WAL file */
|
||||
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
|
||||
#ifdef SQLITE_USE_SEH
|
||||
u32 lockMask; /* Mask of locks held */
|
||||
void *pFree; /* Pointer to sqlite3_free() if exception thrown */
|
||||
int iSysErrno; /* System error code following exception */
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
int nSehTry; /* Number of nested SEH_TRY{} blocks */
|
||||
u8 lockError; /* True if a locking error has occurred */
|
||||
#endif
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
@@ -610,6 +616,100 @@ struct WalIterator {
|
||||
sizeof(ht_slot)*HASHTABLE_NSLOT + HASHTABLE_NPAGE*sizeof(u32) \
|
||||
)
|
||||
|
||||
/*
|
||||
** Structured Exception Handling (SEH) is a Windows-specific technique
|
||||
** for catching exceptions raised while accessing memory-mapped files.
|
||||
**
|
||||
** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and
|
||||
** deal with system-level errors that arise during WAL -shm file processing.
|
||||
** Without this compile-time option, any system-level faults that appear
|
||||
** while accessing the memory-mapped -shm file will cause a process-wide
|
||||
** signal to be deliver, which will more than likely cause the entire
|
||||
** process to exit.
|
||||
*/
|
||||
#ifdef SQLITE_USE_SEH
|
||||
#include <Windows.h>
|
||||
|
||||
/* Beginning of a block of code in which an exception might occur */
|
||||
# define SEH_TRY __try { \
|
||||
assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \
|
||||
VVA_ONLY(pWal->nSehTry++);
|
||||
|
||||
/* The end of a block of code in which an exception might occur */
|
||||
# define SEH_EXCEPT(X) \
|
||||
VVA_ONLY(pWal->nSehTry--); \
|
||||
assert( pWal->nSehTry==0 ); \
|
||||
} __except( sehExceptionFilter(pWal, GetExceptionCode(), GetExceptionInformation() ) ){ X }
|
||||
|
||||
/* Simulate a memory-mapping fault in the -shm file for testing purposes */
|
||||
# define SEH_INJECT_FAULT sehInjectFault(pWal)
|
||||
|
||||
/*
|
||||
** The second argument is the return value of GetExceptionCode() for the
|
||||
** current exception. Return EXCEPTION_EXECUTE_HANDLER if the exception code
|
||||
** indicates that the exception may have been caused by accessing the *-shm
|
||||
** file mapping. Or EXCEPTION_CONTINUE_SEARCH otherwise.
|
||||
*/
|
||||
static int sehExceptionFilter(Wal *pWal, int eCode, EXCEPTION_POINTERS *p){
|
||||
VVA_ONLY(pWal->nSehTry--);
|
||||
if( eCode==EXCEPTION_IN_PAGE_ERROR ){
|
||||
if( p && p->ExceptionRecord && p->ExceptionRecord->NumberParameters>=3 ){
|
||||
/* From MSDN: For this type of exception, the first element of the
|
||||
** ExceptionInformation[] array is a read-write flag - 0 if the exception
|
||||
** was thrown while reading, 1 if while writing. The second element is
|
||||
** the virtual address being accessed. The "third array element specifies
|
||||
** the underlying NTSTATUS code that resulted in the exception". */
|
||||
pWal->iSysErrno = (int)p->ExceptionRecord->ExceptionInformation[2];
|
||||
}
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
/*
|
||||
** If one is configured, invoke the xTestCallback callback with 650 as
|
||||
** the argument. If it returns true, throw the same exception that is
|
||||
** thrown by the system if the *-shm file mapping is accessed after it
|
||||
** has been invalidated.
|
||||
*/
|
||||
static void sehInjectFault(Wal *pWal){
|
||||
int res;
|
||||
assert( pWal->nSehTry>0 );
|
||||
|
||||
res = sqlite3FaultSim(650);
|
||||
if( res!=0 ){
|
||||
ULONG_PTR aArg[3];
|
||||
aArg[0] = 0;
|
||||
aArg[1] = 0;
|
||||
aArg[2] = (ULONG_PTR)res;
|
||||
RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, (const ULONG_PTR*)aArg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** There are two ways to use this macro. To set a pointer to be freed
|
||||
** if an exception is thrown:
|
||||
**
|
||||
** SEH_FREE_ON_ERROR(0, pPtr);
|
||||
**
|
||||
** and to cancel the same:
|
||||
**
|
||||
** SEH_FREE_ON_ERROR(pPtr, 0);
|
||||
**
|
||||
** In the first case, there must not already be a pointer registered to
|
||||
** be freed. In the second case, pPtr must be the registered pointer.
|
||||
*/
|
||||
#define SEH_FREE_ON_ERROR(X,Y) \
|
||||
assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y
|
||||
|
||||
#else
|
||||
# define SEH_TRY VVA_ONLY(pWal->nSehTry++);
|
||||
# define SEH_EXCEPT(X) VVA_ONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 );
|
||||
# define SEH_INJECT_FAULT assert( pWal->nSehTry>0 );
|
||||
# define SEH_FREE_ON_ERROR(X,Y)
|
||||
#endif /* ifdef SQLITE_USE_SEH */
|
||||
|
||||
|
||||
/*
|
||||
** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
|
||||
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
|
||||
@@ -682,6 +782,7 @@ static int walIndexPage(
|
||||
int iPage, /* The page we seek */
|
||||
volatile u32 **ppPage /* Write the page pointer here */
|
||||
){
|
||||
SEH_INJECT_FAULT;
|
||||
if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
|
||||
return walIndexPageRealloc(pWal, iPage, ppPage);
|
||||
}
|
||||
@@ -693,6 +794,7 @@ static int walIndexPage(
|
||||
*/
|
||||
static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
|
||||
assert( pWal->nWiData>0 && pWal->apWiData[0] );
|
||||
SEH_INJECT_FAULT;
|
||||
return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
|
||||
}
|
||||
|
||||
@@ -701,6 +803,7 @@ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
|
||||
*/
|
||||
static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
|
||||
assert( pWal->nWiData>0 && pWal->apWiData[0] );
|
||||
SEH_INJECT_FAULT;
|
||||
return (volatile WalIndexHdr*)pWal->apWiData[0];
|
||||
}
|
||||
|
||||
@@ -958,12 +1061,18 @@ static int walLockShared(Wal *pWal, int lockIdx){
|
||||
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
|
||||
walLockName(lockIdx), rc ? "failed" : "ok"));
|
||||
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
||||
#ifdef SQLITE_USE_SEH
|
||||
if( rc==SQLITE_OK ) pWal->lockMask |= (1 << lockIdx);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
static void walUnlockShared(Wal *pWal, int lockIdx){
|
||||
if( pWal->exclusiveMode ) return;
|
||||
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
|
||||
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
|
||||
#ifdef SQLITE_USE_SEH
|
||||
pWal->lockMask &= ~(1 << lockIdx);
|
||||
#endif
|
||||
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
|
||||
}
|
||||
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
@@ -974,12 +1083,20 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
|
||||
walLockName(lockIdx), n, rc ? "failed" : "ok"));
|
||||
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
||||
#ifdef SQLITE_USE_SEH
|
||||
if( rc==SQLITE_OK ){
|
||||
pWal->lockMask |= (((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
||||
if( pWal->exclusiveMode ) return;
|
||||
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
|
||||
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
|
||||
#ifdef SQLITE_USE_SEH
|
||||
pWal->lockMask &= ~(((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
|
||||
#endif
|
||||
WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
|
||||
walLockName(lockIdx), n));
|
||||
}
|
||||
@@ -1071,6 +1188,7 @@ static int walFramePage(u32 iFrame){
|
||||
*/
|
||||
static u32 walFramePgno(Wal *pWal, u32 iFrame){
|
||||
int iHash = walFramePage(iFrame);
|
||||
SEH_INJECT_FAULT;
|
||||
if( iHash==0 ){
|
||||
return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
|
||||
}
|
||||
@@ -1330,6 +1448,7 @@ static int walIndexRecover(Wal *pWal){
|
||||
/* Malloc a buffer to read frames into. */
|
||||
szFrame = szPage + WAL_FRAME_HDRSIZE;
|
||||
aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
|
||||
SEH_FREE_ON_ERROR(0, aFrame);
|
||||
if( !aFrame ){
|
||||
rc = SQLITE_NOMEM_BKPT;
|
||||
goto recovery_error;
|
||||
@@ -1405,9 +1524,11 @@ static int walIndexRecover(Wal *pWal){
|
||||
}
|
||||
}
|
||||
#endif
|
||||
SEH_INJECT_FAULT;
|
||||
if( iFrame<=iLast ) break;
|
||||
}
|
||||
|
||||
SEH_FREE_ON_ERROR(aFrame, 0);
|
||||
sqlite3_free(aFrame);
|
||||
}
|
||||
|
||||
@@ -1435,6 +1556,7 @@ finished:
|
||||
}else{
|
||||
pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
}
|
||||
SEH_INJECT_FAULT;
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc!=SQLITE_BUSY ){
|
||||
goto recovery_error;
|
||||
@@ -1827,6 +1949,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
||||
memset(p, 0, nByte);
|
||||
p->nSegment = nSegment;
|
||||
aTmp = (ht_slot*)&(((u8*)p)[nByte]);
|
||||
SEH_FREE_ON_ERROR(0, p);
|
||||
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
|
||||
WalHashLoc sLoc;
|
||||
|
||||
@@ -1855,6 +1978,7 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
||||
}
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
SEH_FREE_ON_ERROR(p, 0);
|
||||
walIteratorFree(p);
|
||||
p = 0;
|
||||
}
|
||||
@@ -2080,13 +2204,13 @@ static int walCheckpoint(
|
||||
mxSafeFrame = pWal->hdr.mxFrame;
|
||||
mxPage = pWal->hdr.nPage;
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 y = AtomicLoad(pInfo->aReadMark+i);
|
||||
u32 y = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
|
||||
if( mxSafeFrame>y ){
|
||||
assert( y<=pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
|
||||
AtomicStore(pInfo->aReadMark+i, iMark);
|
||||
AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT;
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
mxSafeFrame = y;
|
||||
@@ -2107,8 +2231,7 @@ static int walCheckpoint(
|
||||
&& (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
|
||||
){
|
||||
u32 nBackfill = pInfo->nBackfill;
|
||||
|
||||
pInfo->nBackfillAttempted = mxSafeFrame;
|
||||
pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT;
|
||||
|
||||
/* Sync the WAL to disk */
|
||||
rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
|
||||
@@ -2139,6 +2262,7 @@ static int walCheckpoint(
|
||||
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
|
||||
i64 iOffset;
|
||||
assert( walFramePgno(pWal, iFrame)==iDbpage );
|
||||
SEH_INJECT_FAULT;
|
||||
if( AtomicLoad(&db->u1.isInterrupted) ){
|
||||
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
|
||||
break;
|
||||
@@ -2168,7 +2292,7 @@ static int walCheckpoint(
|
||||
}
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
AtomicStore(&pInfo->nBackfill, mxSafeFrame);
|
||||
AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2190,6 +2314,7 @@ static int walCheckpoint(
|
||||
*/
|
||||
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
||||
assert( pWal->writeLock );
|
||||
SEH_INJECT_FAULT;
|
||||
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
|
||||
@@ -2221,6 +2346,7 @@ static int walCheckpoint(
|
||||
}
|
||||
|
||||
walcheckpoint_out:
|
||||
SEH_FREE_ON_ERROR(pIter, 0);
|
||||
walIteratorFree(pIter);
|
||||
return rc;
|
||||
}
|
||||
@@ -2243,6 +2369,87 @@ static void walLimitSize(Wal *pWal, i64 nMax){
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SQLITE_USE_SEH
|
||||
/*
|
||||
** This is the "standard" exception handler used in a few places to handle
|
||||
** an exception thrown by reading from the *-shm mapping after it has become
|
||||
** invalid in SQLITE_USE_SEH builds. It is used as follows:
|
||||
**
|
||||
** SEH_TRY { ... }
|
||||
** SEH_EXCEPT( rc = walHandleException(pWal); )
|
||||
**
|
||||
** This function does three things:
|
||||
**
|
||||
** 1) Determines the locks that should be held, based on the contents of
|
||||
** the Wal.readLock, Wal.writeLock and Wal.ckptLock variables. All other
|
||||
** held locks are assumed to be transient locks that would have been
|
||||
** released had the exception not been thrown and are dropped.
|
||||
**
|
||||
** 2) Frees the pointer at Wal.pFree, if any, using sqlite3_free().
|
||||
**
|
||||
** 3) Returns SQLITE_IOERR.
|
||||
*/
|
||||
static int walHandleException(Wal *pWal){
|
||||
if( pWal->exclusiveMode==0 ){
|
||||
static const int S = 1;
|
||||
static const int E = (1<<SQLITE_SHM_NLOCK);
|
||||
int ii;
|
||||
u32 mUnlock = pWal->lockMask & ~(
|
||||
(pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
|
||||
| (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
|
||||
| (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
|
||||
);
|
||||
for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
|
||||
if( (S<<ii) & mUnlock ) walUnlockShared(pWal, ii);
|
||||
if( (E<<ii) & mUnlock ) walUnlockExclusive(pWal, ii, 1);
|
||||
}
|
||||
}
|
||||
sqlite3_free(pWal->pFree);
|
||||
pWal->pFree = 0;
|
||||
return SQLITE_IOERR_IN_PAGE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Assert that the Wal.lockMask mask, which indicates the locks held
|
||||
** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
|
||||
** and Wal.ckptLock variables. To be used as:
|
||||
**
|
||||
** assert( walAssertLockmask(pWal) );
|
||||
*/
|
||||
static int walAssertLockmask(Wal *pWal){
|
||||
if( pWal->exclusiveMode==0 ){
|
||||
static const int S = 1;
|
||||
static const int E = (1<<SQLITE_SHM_NLOCK);
|
||||
u32 mExpect = (
|
||||
(pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
|
||||
| (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
|
||||
| (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
| (pWal->pSnapshot ? (pWal->lockMask & (1 << WAL_CKPT_LOCK)) : 0)
|
||||
#endif
|
||||
);
|
||||
assert( mExpect==pWal->lockMask );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return and zero the "system error" field set when an
|
||||
** EXCEPTION_IN_PAGE_ERROR exception is caught.
|
||||
*/
|
||||
int sqlite3WalSystemErrno(Wal *pWal){
|
||||
int iRet = 0;
|
||||
if( pWal ){
|
||||
iRet = pWal->iSysErrno;
|
||||
pWal->iSysErrno = 0;
|
||||
}
|
||||
return iRet;
|
||||
}
|
||||
|
||||
#else
|
||||
# define walAssertLockmask(x) 1
|
||||
#endif /* ifdef SQLITE_USE_SEH */
|
||||
|
||||
/*
|
||||
** Close a connection to a log file.
|
||||
*/
|
||||
@@ -2257,6 +2464,8 @@ int sqlite3WalClose(
|
||||
if( pWal ){
|
||||
int isDelete = 0; /* True to unlink wal and wal-index files */
|
||||
|
||||
assert( walAssertLockmask(pWal) );
|
||||
|
||||
/* If an EXCLUSIVE lock can be obtained on the database file (using the
|
||||
** ordinary, rollback-mode locking methods, this guarantees that the
|
||||
** connection associated with this log file is the only connection to
|
||||
@@ -2799,6 +3008,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
assert( pWal->nWiData>0 );
|
||||
assert( pWal->apWiData[0]!=0 );
|
||||
pInfo = walCkptInfo(pWal);
|
||||
SEH_INJECT_FAULT;
|
||||
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
|
||||
@@ -2848,7 +3058,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
#endif
|
||||
for(i=1; i<WAL_NREADER; i++){
|
||||
u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
|
||||
u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
|
||||
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
|
||||
assert( thisMark!=READMARK_NOT_USED );
|
||||
mxReadMark = thisMark;
|
||||
@@ -2914,7 +3124,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
** we can guarantee that the checkpointer that set nBackfill could not
|
||||
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
|
||||
*/
|
||||
pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
|
||||
pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
|
||||
walShmBarrier(pWal);
|
||||
if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|
||||
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
|
||||
@@ -2929,6 +3139,53 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
/*
|
||||
** This function does the work of sqlite3WalSnapshotRecover().
|
||||
*/
|
||||
static int walSnapshotRecover(
|
||||
Wal *pWal, /* WAL handle */
|
||||
void *pBuf1, /* Temp buffer pWal->szPage bytes in size */
|
||||
void *pBuf2 /* Temp buffer pWal->szPage bytes in size */
|
||||
){
|
||||
int szPage = (int)pWal->szPage;
|
||||
int rc;
|
||||
i64 szDb; /* Size of db file in bytes */
|
||||
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
|
||||
u32 i = pInfo->nBackfillAttempted;
|
||||
for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
|
||||
WalHashLoc sLoc; /* Hash table location */
|
||||
u32 pgno; /* Page number in db file */
|
||||
i64 iDbOff; /* Offset of db file entry */
|
||||
i64 iWalOff; /* Offset of wal file entry */
|
||||
|
||||
rc = walHashGet(pWal, walFramePage(i), &sLoc);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
pgno = sLoc.aPgno[i-sLoc.iZero];
|
||||
iDbOff = (i64)(pgno-1) * szPage;
|
||||
|
||||
if( iDbOff+szPage<=szDb ){
|
||||
iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
|
||||
rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pInfo->nBackfillAttempted = i-1;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to reduce the value of the WalCkptInfo.nBackfillAttempted
|
||||
** variable so that older snapshots can be accessed. To do this, loop
|
||||
@@ -2954,50 +3211,21 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
|
||||
assert( pWal->readLock>=0 );
|
||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
|
||||
int szPage = (int)pWal->szPage;
|
||||
i64 szDb; /* Size of db file in bytes */
|
||||
|
||||
rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
|
||||
if( rc==SQLITE_OK ){
|
||||
void *pBuf1 = sqlite3_malloc(szPage);
|
||||
void *pBuf2 = sqlite3_malloc(szPage);
|
||||
void *pBuf1 = sqlite3_malloc(pWal->szPage);
|
||||
void *pBuf2 = sqlite3_malloc(pWal->szPage);
|
||||
if( pBuf1==0 || pBuf2==0 ){
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
u32 i = pInfo->nBackfillAttempted;
|
||||
for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
|
||||
WalHashLoc sLoc; /* Hash table location */
|
||||
u32 pgno; /* Page number in db file */
|
||||
i64 iDbOff; /* Offset of db file entry */
|
||||
i64 iWalOff; /* Offset of wal file entry */
|
||||
|
||||
rc = walHashGet(pWal, walFramePage(i), &sLoc);
|
||||
if( rc!=SQLITE_OK ) break;
|
||||
assert( i - sLoc.iZero - 1 >=0 );
|
||||
pgno = sLoc.aPgno[i-sLoc.iZero-1];
|
||||
iDbOff = (i64)(pgno-1) * szPage;
|
||||
|
||||
if( iDbOff+szPage<=szDb ){
|
||||
iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
|
||||
rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
|
||||
}
|
||||
|
||||
if( rc!=SQLITE_OK || 0==memcmp(pBuf1, pBuf2, szPage) ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pInfo->nBackfillAttempted = i-1;
|
||||
pWal->ckptLock = 1;
|
||||
SEH_TRY {
|
||||
rc = walSnapshotRecover(pWal, pBuf1, pBuf2);
|
||||
}
|
||||
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
||||
pWal->ckptLock = 0;
|
||||
}
|
||||
|
||||
sqlite3_free(pBuf1);
|
||||
sqlite3_free(pBuf2);
|
||||
}
|
||||
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
}
|
||||
|
||||
@@ -3006,28 +3234,20 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
|
||||
#endif /* SQLITE_ENABLE_SNAPSHOT */
|
||||
|
||||
/*
|
||||
** Begin a read transaction on the database.
|
||||
**
|
||||
** This routine used to be called sqlite3OpenSnapshot() and with good reason:
|
||||
** it takes a snapshot of the state of the WAL and wal-index for the current
|
||||
** instant in time. The current thread will continue to use this snapshot.
|
||||
** Other threads might append new content to the WAL and wal-index but
|
||||
** that extra content is ignored by the current thread.
|
||||
**
|
||||
** If the database contents have changes since the previous read
|
||||
** transaction, then *pChanged is set to 1 before returning. The
|
||||
** Pager layer will use this to know that its cache is stale and
|
||||
** needs to be flushed.
|
||||
** This function does the work of sqlite3WalBeginReadTransaction() (see
|
||||
** below). That function simply calls this one inside an SEH_TRY{...} block.
|
||||
*/
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
static int walBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
int rc; /* Return code */
|
||||
int cnt = 0; /* Number of TryBeginRead attempts */
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
int ckptLock = 0;
|
||||
int bChanged = 0;
|
||||
WalIndexHdr *pSnapshot = pWal->pSnapshot;
|
||||
#endif
|
||||
|
||||
assert( pWal->ckptLock==0 );
|
||||
assert( pWal->nSehTry>0 );
|
||||
|
||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||
if( pSnapshot ){
|
||||
@@ -3050,7 +3270,7 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
pWal->ckptLock = 1;
|
||||
ckptLock = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -3114,15 +3334,37 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
}
|
||||
|
||||
/* Release the shared CKPT lock obtained above. */
|
||||
if( pWal->ckptLock ){
|
||||
if( ckptLock ){
|
||||
assert( pSnapshot );
|
||||
walUnlockShared(pWal, WAL_CKPT_LOCK);
|
||||
pWal->ckptLock = 0;
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Begin a read transaction on the database.
|
||||
**
|
||||
** This routine used to be called sqlite3OpenSnapshot() and with good reason:
|
||||
** it takes a snapshot of the state of the WAL and wal-index for the current
|
||||
** instant in time. The current thread will continue to use this snapshot.
|
||||
** Other threads might append new content to the WAL and wal-index but
|
||||
** that extra content is ignored by the current thread.
|
||||
**
|
||||
** If the database contents have changes since the previous read
|
||||
** transaction, then *pChanged is set to 1 before returning. The
|
||||
** Pager layer will use this to know that its cache is stale and
|
||||
** needs to be flushed.
|
||||
*/
|
||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||
int rc;
|
||||
SEH_TRY {
|
||||
rc = walBeginReadTransaction(pWal, pChanged);
|
||||
}
|
||||
SEH_EXCEPT( rc = walHandleException(pWal); )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finish with a read transaction. All this does is release the
|
||||
** read-lock.
|
||||
@@ -3143,7 +3385,7 @@ void sqlite3WalEndReadTransaction(Wal *pWal){
|
||||
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
|
||||
** error does occur, the final value of *piRead is undefined.
|
||||
*/
|
||||
int sqlite3WalFindFrame(
|
||||
static int walFindFrame(
|
||||
Wal *pWal, /* WAL handle */
|
||||
Pgno pgno, /* Database page number to read data for */
|
||||
u32 *piRead /* OUT: Frame number (or zero) */
|
||||
@@ -3206,6 +3448,7 @@ int sqlite3WalFindFrame(
|
||||
}
|
||||
nCollide = HASHTABLE_NSLOT;
|
||||
iKey = walHash(pgno);
|
||||
SEH_INJECT_FAULT;
|
||||
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
|
||||
u32 iFrame = iH + sLoc.iZero;
|
||||
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
|
||||
@@ -3242,6 +3485,30 @@ int sqlite3WalFindFrame(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search the wal file for page pgno. If found, set *piRead to the frame that
|
||||
** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
|
||||
** to zero.
|
||||
**
|
||||
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
|
||||
** error does occur, the final value of *piRead is undefined.
|
||||
**
|
||||
** The difference between this function and walFindFrame() is that this
|
||||
** function wraps walFindFrame() in an SEH_TRY{...} block.
|
||||
*/
|
||||
int sqlite3WalFindFrame(
|
||||
Wal *pWal, /* WAL handle */
|
||||
Pgno pgno, /* Database page number to read data for */
|
||||
u32 *piRead /* OUT: Frame number (or zero) */
|
||||
){
|
||||
int rc;
|
||||
SEH_TRY {
|
||||
rc = walFindFrame(pWal, pgno, piRead);
|
||||
}
|
||||
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read the contents of frame iRead from the wal file into buffer pOut
|
||||
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
|
||||
@@ -3323,12 +3590,17 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
||||
** time the read transaction on this connection was started, then
|
||||
** the write is disallowed.
|
||||
*/
|
||||
SEH_TRY {
|
||||
if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
pWal->writeLock = 0;
|
||||
rc = SQLITE_BUSY_SNAPSHOT;
|
||||
}
|
||||
}
|
||||
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
||||
|
||||
if( rc!=SQLITE_OK ){
|
||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||
pWal->writeLock = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3364,6 +3636,7 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||
Pgno iMax = pWal->hdr.mxFrame;
|
||||
Pgno iFrame;
|
||||
|
||||
SEH_TRY {
|
||||
/* Restore the clients cache of the wal-index header to the state it
|
||||
** was in before the client began writing to the database.
|
||||
*/
|
||||
@@ -3389,6 +3662,8 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||
}
|
||||
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
|
||||
}
|
||||
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3431,8 +3706,11 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
|
||||
pWal->hdr.mxFrame = aWalData[0];
|
||||
pWal->hdr.aFrameCksum[0] = aWalData[1];
|
||||
pWal->hdr.aFrameCksum[1] = aWalData[2];
|
||||
SEH_TRY {
|
||||
walCleanupHash(pWal);
|
||||
}
|
||||
SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -3612,7 +3890,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
|
||||
** Write a set of frames to the log. The caller must hold the write-lock
|
||||
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
|
||||
*/
|
||||
int sqlite3WalFrames(
|
||||
static int walFrames(
|
||||
Wal *pWal, /* Wal handle to write to */
|
||||
int szPage, /* Database page-size in bytes */
|
||||
PgHdr *pList, /* List of dirty pages to write */
|
||||
@@ -3723,7 +4001,7 @@ int sqlite3WalFrames(
|
||||
** checksums must be recomputed when the transaction is committed. */
|
||||
if( iFirst && (p->pDirty || isCommit==0) ){
|
||||
u32 iWrite = 0;
|
||||
VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
|
||||
VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite);
|
||||
assert( rc==SQLITE_OK || iWrite==0 );
|
||||
if( iWrite>=iFirst ){
|
||||
i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
|
||||
@@ -3842,6 +4120,29 @@ int sqlite3WalFrames(
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Write a set of frames to the log. The caller must hold the write-lock
|
||||
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
|
||||
**
|
||||
** The difference between this function and walFrames() is that this
|
||||
** function wraps walFrames() in an SEH_TRY{...} block.
|
||||
*/
|
||||
int sqlite3WalFrames(
|
||||
Wal *pWal, /* Wal handle to write to */
|
||||
int szPage, /* Database page-size in bytes */
|
||||
PgHdr *pList, /* List of dirty pages to write */
|
||||
Pgno nTruncate, /* Database size after this commit */
|
||||
int isCommit, /* True if this is a commit */
|
||||
int sync_flags /* Flags to pass to OsSync() (or 0) */
|
||||
){
|
||||
int rc;
|
||||
SEH_TRY {
|
||||
rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags);
|
||||
}
|
||||
SEH_EXCEPT( rc = walHandleException(pWal); )
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This routine is called to implement sqlite3_wal_checkpoint() and
|
||||
** related interfaces.
|
||||
@@ -3921,6 +4222,7 @@ int sqlite3WalCheckpoint(
|
||||
|
||||
|
||||
/* Read the wal-index header. */
|
||||
SEH_TRY {
|
||||
if( rc==SQLITE_OK ){
|
||||
walDisableBlocking(pWal);
|
||||
rc = walIndexReadHdr(pWal, &isChanged);
|
||||
@@ -3932,7 +4234,6 @@ int sqlite3WalCheckpoint(
|
||||
|
||||
/* Copy data from the log to the database file. */
|
||||
if( rc==SQLITE_OK ){
|
||||
|
||||
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
@@ -3942,9 +4243,12 @@ int sqlite3WalCheckpoint(
|
||||
/* If no error occurred, set the output variables. */
|
||||
if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
|
||||
if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
|
||||
SEH_INJECT_FAULT;
|
||||
if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
|
||||
}
|
||||
}
|
||||
}
|
||||
SEH_EXCEPT( rc = walHandleException(pWal); )
|
||||
|
||||
if( isChanged ){
|
||||
/* If a new wal-index header was loaded before the checkpoint was
|
||||
@@ -4021,7 +4325,9 @@ int sqlite3WalExclusiveMode(Wal *pWal, int op){
|
||||
** locks are taken in this case). Nor should the pager attempt to
|
||||
** upgrade to exclusive-mode following such an error.
|
||||
*/
|
||||
#ifndef SQLITE_USE_SEH
|
||||
assert( pWal->readLock>=0 || pWal->lockError );
|
||||
#endif
|
||||
assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
|
||||
|
||||
if( op==0 ){
|
||||
@@ -4122,6 +4428,7 @@ int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
|
||||
*/
|
||||
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
|
||||
int rc;
|
||||
SEH_TRY {
|
||||
rc = walLockShared(pWal, WAL_CKPT_LOCK);
|
||||
if( rc==SQLITE_OK ){
|
||||
WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
|
||||
@@ -4132,6 +4439,8 @@ int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
|
||||
walUnlockShared(pWal, WAL_CKPT_LOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
SEH_EXCEPT( rc = walHandleException(pWal); )
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@@ -151,5 +151,9 @@ int sqlite3WalWriteLock(Wal *pWal, int bLock);
|
||||
void sqlite3WalDb(Wal *pWal, sqlite3 *db);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_USE_SEH
|
||||
int sqlite3WalSystemErrno(Wal*);
|
||||
#endif
|
||||
|
||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||
#endif /* SQLITE_WAL_H */
|
||||
|
@@ -923,9 +923,15 @@ do_execsql_test json-20.3 {
|
||||
# a NULL value as the JSON input.
|
||||
#
|
||||
db null NULL
|
||||
do_execsql_test json-21.1 {
|
||||
if {[db exists {SELECT * FROM pragma_compile_options WHERE compile_options LIKE '%legacy_json_valid%'}]} {
|
||||
do_execsql_test json-21.1-legacy {
|
||||
SELECT json_valid(NULL);
|
||||
} 0
|
||||
} else {
|
||||
do_execsql_test json-21.1-correct {
|
||||
SELECT json_valid(NULL);
|
||||
} NULL
|
||||
}
|
||||
do_execsql_test json-21.2 {
|
||||
SELECT json_error_position(NULL);
|
||||
} NULL
|
||||
|
@@ -23,6 +23,7 @@ set testprefix snapshot_fault
|
||||
# checkpointing the db.
|
||||
#
|
||||
do_faultsim_test 1.0 -prep {
|
||||
catch { db2 close }
|
||||
faultsim_delete_and_reopen
|
||||
sqlite3 db2 test.db
|
||||
db2 eval {
|
||||
|
150
test/walseh1.test
Normal file
150
test/walseh1.test
Normal file
@@ -0,0 +1,150 @@
|
||||
# 2021 August 16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix walseh1
|
||||
|
||||
set ::seh_countdown 0
|
||||
set ::seh_errno 10
|
||||
proc seh_faultsim_callback {iFault} {
|
||||
if {$iFault==650} {
|
||||
incr ::seh_countdown -1
|
||||
if {$::seh_countdown==0} { return $::seh_errno }
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
proc seh_injectinstall {} {
|
||||
sqlite3_test_control_fault_install seh_faultsim_callback
|
||||
}
|
||||
proc seh_injectuninstall {} {
|
||||
sqlite3_test_control_fault_install
|
||||
}
|
||||
proc seh_injectstart {iFail} {
|
||||
set ::seh_errno [expr 2+$iFail*10]
|
||||
set ::seh_countdown $iFail
|
||||
}
|
||||
proc seh_injectstop {} {
|
||||
set res [expr $::seh_countdown<=0]
|
||||
set ::seh_countdown 0
|
||||
set res
|
||||
}
|
||||
|
||||
set FAULTSIM(seh) [list \
|
||||
-injectinstall seh_injectinstall \
|
||||
-injectstart seh_injectstart \
|
||||
-injectstop seh_injectstop \
|
||||
-injecterrlist {{1 {disk I/O error}}} \
|
||||
-injectuninstall seh_injectuninstall \
|
||||
]
|
||||
|
||||
proc test_system_errno {db expect} {
|
||||
set serrno [sqlite3_system_errno $db]
|
||||
if {$serrno!=$expect} {
|
||||
error "surprising system_errno. Expected $expect, got $serrno"
|
||||
}
|
||||
}
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA journal_mode = wal;
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
} {wal}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -faults seh -prep {
|
||||
catch { db2 close }
|
||||
faultsim_restore_and_reopen
|
||||
execsql { SELECT * FROM sqlite_schema }
|
||||
sqlite3 db2 test.db
|
||||
} -body {
|
||||
execsql { SELECT * FROM t1 } db2
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4}}
|
||||
if {$testrc} { test_system_errno db2 $::seh_errno }
|
||||
}
|
||||
catch { db2 close }
|
||||
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 2 -faults seh -prep {
|
||||
catch { db close }
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { SELECT * FROM t1 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4}}
|
||||
if {$testrc} { test_system_errno db $::seh_errno }
|
||||
}
|
||||
|
||||
do_faultsim_test 3 -faults seh -prep {
|
||||
catch { db close }
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { INSERT INTO t1 VALUES(5, 6) }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4 5 6}}
|
||||
if {$testrc} { test_system_errno db $::seh_errno }
|
||||
}
|
||||
|
||||
do_faultsim_test 4 -faults seh -prep {
|
||||
catch { db close }
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { PRAGMA wal_checkpoint }
|
||||
execsql { INSERT INTO t1 VALUES(7, 8) }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4 7 8}}
|
||||
if {$testrc} { test_system_errno db $::seh_errno }
|
||||
}
|
||||
catch { db close }
|
||||
|
||||
do_faultsim_test 5 -faults seh -prep {
|
||||
catch { db close }
|
||||
faultsim_restore_and_reopen
|
||||
execsql {
|
||||
PRAGMA cache_size = 5;
|
||||
BEGIN;
|
||||
WITH s(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<50
|
||||
)
|
||||
INSERT INTO t1 SELECT randomblob(500), randomblob(500) FROM s;
|
||||
}
|
||||
} -body {
|
||||
execsql ROLLBACK
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
if {$testrc} { test_system_errno db $::seh_errno }
|
||||
}
|
||||
catch { db close }
|
||||
|
||||
do_faultsim_test 6 -faults seh -prep {
|
||||
catch { db close }
|
||||
faultsim_restore_and_reopen
|
||||
} -body {
|
||||
execsql { PRAGMA wal_checkpoint = TRUNCATE }
|
||||
execsql { INSERT INTO t1 VALUES(7, 8) }
|
||||
execsql { SELECT * FROM t1 }
|
||||
} -test {
|
||||
faultsim_test_result {0 {1 2 3 4 7 8}}
|
||||
if {$testrc} { test_system_errno db $::seh_errno }
|
||||
}
|
||||
catch { db close }
|
||||
|
||||
finish_test
|
||||
|
||||
|
@@ -180,6 +180,7 @@ set boolean_defnil_options {
|
||||
SQLITE_IGNORE_FLOCK_LOCK_ERRORS
|
||||
SQLITE_INLINE_MEMCPY
|
||||
SQLITE_INT64_TYPE
|
||||
SQLITE_LEGACY_JSON_VALID
|
||||
SQLITE_LIKE_DOESNT_MATCH_BLOBS
|
||||
SQLITE_LOCK_TRACE
|
||||
SQLITE_LOG_CACHE_SPILL
|
||||
|
Reference in New Issue
Block a user